Using XSLT to create a well formatted nested table from unknown XML

让人想犯罪 __ 提交于 2019-12-23 02:43:07

问题


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>

回答1:


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



来源:https://stackoverflow.com/questions/31393368/using-xslt-to-create-a-well-formatted-nested-table-from-unknown-xml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!