使用XSLT从未知的XML创建格式良好的嵌套表 [英] Using XSLT to create a well formatted nested table from unknown XML

查看:191
本文介绍了使用XSLT从未知的XML创建格式良好的嵌套表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我所提供的任务:
我的老板希望我创建一个XSLT,它将一个未知结构的XML,并将其放入一个嵌套表(标签名称作为表头)尽可能不重复表头。我几乎能够得到他想要的东西(表)



问题:
我只用XSLT现在几天(已经通过了几个教程,玩了一下),所以如果有人能指出我在哪里可以找到有助于我解决问题的信息的方向,那将是非常感激的。 >

环境数据:我正在使用XSLT和PHP(DOM对象)。我的老板要我成为XSLT公司的专家,所以如果可以通过纯粹的XSLT,那将不胜感激。



附加信息:应人员的要求,附加信息(代码)在下面。任务是将下面的XML代码片段转换到下表中进行显示。不幸的是,我现在的代码处于现在的状态,所以我不会发布(如果这个问题在我再次稳定的时候仍然是开放的,我会发布)。



XML片段:

 < root> 
< request>
< details>
< columnname> name1< / columnname>
< operator>< / operator>
< value> val< / value>
< seq> 1< / seq>
< / details>
< / request>
< request>
< details>
< columnname> name2< / columnname>
< operator> OP< / operator>
< value> val< / value>
< seq> 2< / seq>
< / details>
< / request>
< request>
< details>
< columnname> name3< / columnname>
< value> val< / value>
< seq> 3< / seq>
< / details>
< / request>
< response>
< details>
< columnname> name4< / columnname>
< value> val< / value>
< seq> 4< / seq>
< / details>
< / response>
< / root>

期望的输出

 < table border =1style =border-collapse:collapse; width:100%> 
< tr>
< th>根< / th>
< / tr>
< tr>
< td>
< table border =1style =border-collapse:collapse; width:100%>
< tr>
< th>请求< / th>
< th>响应< / th>
< / tr>
< tr>
< td>
< table border =1style =border-collapse:collapse; width:100%>
< tr>
< th>细节< / th>
< / tr>
< tr>
< td>
< table border =1style =border-collapse:collapse; width:100%>
< tr>
< th>列名< / th>
< th>运算符< / th>
< th>值< / th>
< th> seq< / th>
< / tr>
< tr>
< td> name1< / td>
< td>< / td>
< td> val< / td>
< td> 1< / td>
< / tr>
< tr>
< td> name2< / td>
< td> OP< / td>
< td> val< / td>
< td> 2< / td>
< / tr>
< tr>
< td> name3< / td>
< td>< / td>
< td> val< / td>
< td> 3< / td>
< / tr>
< / table>
< / td>
< / tr>
< / table>
< / td>
< td>
< table border =1style =border-collapse:collapse; width:100%>
< tr>
< th>细节< / th>
< / tr>
< tr>
< td>
< table border =1style =border-collapse:collapse; width:100%>
< tr>
< th>列名< / th>
< th>值< / th>
< th> seq< / th>
< / tr>
< tr>
< td> name4< / td>
< td> val< / td>
< td> 4< / td>
< / tr>
< / table>
< / td>
< / tr>
< / table>
< / td>
< / tr>
< / table>
< / td>
< / tr>
< / table>

对michael.hor257k的回复:看起来像这样。 / p>

 < table border =1style =border-collapse:collapse; width:100%> 
< tr>
< th>根< / th>
< / tr>
< tr>
< td>
< table border =1style =border-collapse:collapse; width:100%>
< tr>
< th>父< / th>
< th>叔叔< / th>
< / tr>
< tr>
< td>
< table border =1style =border-collapse:collapse; width:100%>
< tr>
< th> child< / th>
< th>侄子< / th>
< / tr>
< tr>
< td>
< table border =1style =border-collapse:collapse; width:100%>
< tr>
< th> string< / th>
< th> number< / th>
< th>孙子< / th>
< th> date< / th>
< / tr>
< tr>
< td> A< / td>
< td>< / td>
< td>< / td>
< td>< / td>
< / tr>
< tr>
< td> B< / td>
< td>< / td>
< td>< / td>
< td>< / td>
< / tr>
< tr>
< td> C< / td>
< td> 1< / td>
< td>
< table border =1style =border-collapse:collapse; width:100%>
< tr>
< th> string< / th>
< th>子串< / th>
< th> number< / th>
< / tr>
< tr>
< td> DD< / td>
< td> EE< / td>
< td> 33< / td>
< / tr>
< / table>
< / td>
< td>< / td>
< / tr>
< tr>
< td>< / td>
< td> 2< / td>
< td>< / td>
< td>< / td>
< / tr>
< tr>
< td> F< / td>
< td>< / td>
< td>< / td>
< td> 2015-02-12< / td>
< / tr>
< / table>
< / td>
< td>
< table border =1style =border-collapse:collapse; width:100%>
< tr>
< th> string< / th>
< / tr>
< tr>
< td> G< / td>
< / tr>
< / table>
< / td>
< / tr>
< / table>
< / td>
< td>
< table border =1style =border-collapse:collapse; width:100%>
< tr>
< th>侄女< / th>
< / tr>
< tr>
< td>
< table border =1style =border-collapse:collapse; width:100%>
< tr>
< th> string< / th>
< / tr>
< tr>
< td> H< / td>
< / tr>
< / table>
< / td>
< / tr>
< / table>
< / td>
< / tr>
< / table>
< / td>
< / tr>
< / table>


解决方案

正如我在评论中所说,要简单基本上,您要删除具有相同路径的任何重复节点(仅使用节点名称计算路径),并显示生成的层次结构。



这需要进行预处理通行,以分配所有节点的路径。我们还需要为每个节点提供其父路径,以便以后可以由其新父(以前可能是其叔叔或大叔或...)调用。



在第二和最后一步中,我们将应用 Muenchian grouping 到第一遍的结果,仅通过路径留下不同的节点。



在这个例子中,我将只处理元素,结果将显示为一个无序列表。



XSLT 1.0

 < xsl:stylesheet version =1.0
xmlns:xsl =http://www.w3.org/1999/XSL/Transform
xmlns:exsl =http:// exslt.org/common
extension-element-prefixes =exsl>
< xsl:output method =xmlversion =1.0encoding =UTF-8indent =yes/>
< xsl:strip-space elements =*/>

< xsl:key name =node-by-pathmatch =nodeuse =@ path/>
< xsl:key name =node-by-parent-pathmatch =nodeuse =@ parent-path/>

< xsl:template match =/>
<! - first-pass - >
< xsl:variable name =first-pass>
< xsl:apply-templates select =*mode =firstpass/>
< / xsl:variable>
<! - 输出 - >
< ul>
< xsl:apply-templates select =exsl:node-set($ first-pass)/ node [@ parent-path ='']/>
< / ul>
< / xsl:template>

< xsl:template match =*mode =firstpass>
< xsl:variable name =parent-path>
< xsl:for-each select =ancestor :: *>
< xsl:value-of select =concat('/',name())/>
< / xsl:for-each>
< / xsl:variable>
< node name ={name()}parent-path ={$ parent-path}path ={concat($ parent-path,'/',name())}> ;
< xsl:apply-templates select =*mode =firstpass/>
< / node>
< / xsl:template>

< xsl:template match =node>
< li>
< xsl:value-of select =@ name/>
< xsl:variable name =nextselect =key('node-by-parent-path',@path)/>
< xsl:if test =$ next>
< ul>
< xsl:apply-templates select =$ next [count(。| key('node-by-path',@path)[1])= 1]/>
< / ul>
< / xsl:if>
< / li>
< / xsl:template>

< / xsl:stylesheet>

测试输入XML

 < root> 
< parent>
< child>
< string> A< / string>
< string> B< / string>
< / child>
< child>
< string> C< / string>
< number> 1< / number>
< number> 2< / number>
< grandchild>
< string> DD< / string>
< substring> EE< / substring>
< number> 33< / number>
< / grandchild>
< / child>
< / parent>
< parent>
< child>
< string> F< / string>
< date> 2015-02-12< / date>
< / child>
< nephew>
< string> G< / string>
< / nephew>
< / parent>
<叔叔>
< niece>
< string> H< / string>
< / niece>
< / uncle>
< / root>

结果

 <?xml version =1.0encoding =UTF-8?> 
< ul>
< li>根< ul>
< li>父< ul>
< li> child< ul>
< li> string< / li>
< li> number< / li>
< li>孙子< ul>
< li> string< / li>
< li>子串< / li>
< li> number< / li>
< / ul>
< / li>
< li> date< / li>
< / ul>
< / li>
< li>侄子< ul>
< li> string< / li>
< / ul>
< / li>
< / ul>
< / li>
< li>叔叔< ul>
< li>侄女< ul>
< li> string< / li>
< / ul>
< / li>
< / ul>
< / li>
< / ul>
< / li>
< / ul>

呈现




The task I was given: My boss wants me to create an XSLT that takes XML of an unknown structure, and put it into a nested table (tag names as table headers) without repeating table headers where possible. I was almost able to get what he wants (The table )

The question: I have only worked with XSLT's for a few days now (have gone through a few tutorials and played with it a bit), So if anyone can point me in a good direction on where to find information that will help me with my problem, it would be greatly appreciated.

Environment Data: I am working with XSLT and PHP (DOM objects). My boss wants me to become the companies XSLT expert, so if it is possible through pure XSLT, it would be appreciated.

Additional info: At the request of the people responding, additional info (code) is below.The task is to turn something like the XML snippet below into the table below for displaying. Unfortunately, the code I had is in a state of flux at the moment, so I will not be posting it (if the question is still open when I get it stable again, I will post it).

XML Snippet:

<root>
    <request>
        <details>
            <columnname>name1</columnname>
            <operator></operator>
            <value>val</value>
            <seq>1</seq>
        </details>
    </request>
    <request>
        <details>
            <columnname>name2</columnname>
            <operator>OP</operator>
            <value>val</value>
            <seq>2</seq>
        </details>
    </request>
    <request>
        <details>
            <columnname>name3</columnname>
            <value>val</value>
            <seq>3</seq>
        </details>
    </request>
    <response>
        <details>
            <columnname>name4</columnname>
            <value>val</value>
            <seq>4</seq>
        </details>
    </response>
</root>

Desired Output

<table border="1" style="border-collapse:collapse;width:100%">
    <tr>
        <th>root</th>
    </tr>
    <tr>
        <td>
            <table border="1" style="border-collapse:collapse;width:100%">
                <tr>
                    <th>request</th>
                    <th>response</th>
                </tr>
                <tr>
                    <td>
                        <table border="1" style="border-collapse:collapse;width:100%">
                            <tr>
                                <th>details</th>
                            </tr>
                            <tr>
                                <td>
                                    <table border="1" style="border-collapse:collapse;width:100%">
                                        <tr>
                                            <th>columnname</th>
                                            <th>operator</th>
                                            <th>value</th>
                                            <th>seq</th>
                                        </tr>
                                        <tr>
                                            <td>name1</td>
                                            <td></td>
                                            <td>val</td>
                                            <td>1</td>
                                        </tr>
                                        <tr>
                                            <td>name2</td>
                                            <td>OP</td>
                                            <td>val</td>
                                            <td>2</td>
                                        </tr>
                                        <tr>
                                            <td>name3</td>
                                            <td></td>
                                            <td>val</td>
                                            <td>3</td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                        </table>
                    </td>
                    <td>
                        <table border="1" style="border-collapse:collapse;width:100%">
                            <tr>
                                <th>details</th>
                            </tr>
                            <tr>
                                <td>
                                    <table border="1" style="border-collapse:collapse;width:100%">
                                        <tr>
                                            <th>columnname</th>
                                            <th>value</th>
                                            <th>seq</th>
                                        </tr>
                                        <tr>
                                            <td>name4</td>
                                            <td>val</td>
                                            <td>4</td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </td>
    </tr>
</table>

Response to michael.hor257k: It would look something like this.

<table border="1" style="border-collapse:collapse;width:100%">
    <tr>
        <th>root</th>
    </tr>
    <tr>
        <td>
            <table border="1" style="border-collapse:collapse;width:100%">
                <tr>
                    <th>parent</th>
                    <th>uncle</th>
                </tr>
                <tr>
                    <td>
                        <table border="1" style="border-collapse:collapse;width:100%">
                            <tr>
                                <th>child</th>
                                <th>nephew</th>
                            </tr>
                            <tr>
                                <td>
                                    <table border="1" style="border-collapse:collapse;width:100%">
                                        <tr>
                                            <th>string</th>
                                            <th>number</th>
                                            <th>grandchild</th>
                                            <th>date</th>
                                        </tr>
                                        <tr>
                                            <td>A</td>
                                            <td></td>
                                            <td></td>
                                            <td></td>
                                        </tr>
                                        <tr>
                                            <td>B</td>
                                            <td></td>
                                            <td></td>
                                            <td></td>
                                        </tr>
                                        <tr>
                                            <td>C</td>
                                            <td>1</td>
                                            <td>
                                                <table border="1" style="border-collapse:collapse;width:100%">
                                                    <tr>
                                                        <th>string</th>
                                                        <th>substring</th>
                                                        <th>number</th>
                                                    </tr>
                                                    <tr>
                                                        <td>DD</td>
                                                        <td>EE</td>
                                                        <td>33</td>
                                                    </tr>
                                                </table>
                                            </td>
                                            <td></td>
                                        </tr>
                                        <tr>
                                            <td></td>
                                            <td>2</td>
                                            <td></td>
                                            <td></td>
                                        </tr>
                                        <tr>
                                            <td>F</td>
                                            <td></td>
                                            <td></td>
                                            <td>2015-02-12</td>
                                        </tr>
                                    </table>
                                </td>
                                <td>
                                    <table border="1" style="border-collapse:collapse;width:100%">
                                        <tr>
                                            <th>string</th>
                                        </tr>
                                        <tr>
                                            <td>G</td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                        </table>
                    </td>
                    <td>
                        <table border="1" style="border-collapse:collapse;width:100%">
                            <tr>
                                <th>niece</th>
                            </tr>
                            <tr>
                                <td>
                                    <table border="1" style="border-collapse:collapse;width:100%">
                                        <tr>
                                            <th>string</th>
                                        </tr>
                                        <tr>
                                            <td>H</td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </td>
    </tr>
</table>

解决方案

As I said in the comments, this is not going to be simple. Basically, you want to remove any duplicate nodes that have the same path (where a path is calculated using only node names) and display the resulting hierarchy.

This requires making a pre-processing pass to assign all nodes their path. We also need to provide each node with its parent path - so that it can be called later by its new parent (which formerly could be its uncle or great-uncle or...).

In the second - and final - step we will be applying Muenchian grouping to the result of the first pass, leaving only distinct nodes by path.

In this example I will be processing only elements, and the result will be presented as an unordered list.

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="node-by-path" match="node" use="@path" />
<xsl:key name="node-by-parent-path" match="node" use="@parent-path" />

<xsl:template match="/">
    <!-- first-pass -->
    <xsl:variable name="first-pass">
        <xsl:apply-templates select="*" mode="firstpass"/>
    </xsl:variable>
    <!-- output -->
    <ul>
        <xsl:apply-templates select="exsl:node-set($first-pass)/node[@parent-path='']" />
    </ul>
</xsl:template>

<xsl:template match="*" mode="firstpass">
    <xsl:variable name="parent-path">
        <xsl:for-each select="ancestor::*">
            <xsl:value-of select="concat('/', name())"/>
        </xsl:for-each>                 
    </xsl:variable> 
    <node name="{name()}" parent-path="{$parent-path}" path="{concat($parent-path, '/', name())}">
        <xsl:apply-templates select="*" mode="firstpass"/>
    </node>
</xsl:template>

<xsl:template match="node">
    <li>
        <xsl:value-of select="@name"/>
        <xsl:variable name="next" select="key('node-by-parent-path', @path)" />
        <xsl:if test="$next">
            <ul>
                <xsl:apply-templates select="$next[count(. | key('node-by-path', @path)[1]) = 1]"/>
            </ul>
        </xsl:if>
    </li>
</xsl:template> 

</xsl:stylesheet>

Test input XML

<root>
   <parent>
      <child>
         <string>A</string>
         <string>B</string>
      </child>
      <child>
         <string>C</string>
         <number>1</number>
         <number>2</number>
         <grandchild>
            <string>DD</string>
            <substring>EE</substring>
            <number>33</number>
         </grandchild>
      </child>
   </parent>
   <parent>
      <child>
         <string>F</string>
         <date>2015-02-12</date>
      </child>
      <nephew>
         <string>G</string>
      </nephew>
   </parent>
   <uncle>
      <niece>
         <string>H</string>
      </niece>
   </uncle>
</root>

Result

<?xml version="1.0" encoding="UTF-8"?>
<ul>
   <li>root<ul>
         <li>parent<ul>
               <li>child<ul>
                     <li>string</li>
                     <li>number</li>
                     <li>grandchild<ul>
                           <li>string</li>
                           <li>substring</li>
                           <li>number</li>
                        </ul>
                     </li>
                     <li>date</li>
                  </ul>
               </li>
               <li>nephew<ul>
                     <li>string</li>
                  </ul>
               </li>
            </ul>
         </li>
         <li>uncle<ul>
               <li>niece<ul>
                     <li>string</li>
                  </ul>
               </li>
            </ul>
         </li>
      </ul>
   </li>
</ul>

Rendered

这篇关于使用XSLT从未知的XML创建格式良好的嵌套表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆