问题
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