XSL: Build a unique map from child nodes in multiple xml files, then display it in a table
Use XSL to build a unique map from child nodes, then display it in a table
I would like to create a xsl that takes the following xml documents as input
Source.xml
<root>
<children>
<child>
Source-A
</child>
<child>
Source-B
</child>
</children>
</root>
Source-A.xml
<child>
<Objects>
<Object>
<Key>Key-1234</Key>
</Object>
<Object>
<Key>Key-5678</Key>
</Object>
</Objects>
</child>
Source-B.xml
<child>
<Objects>
<Object>
<Key>Key-5678</Key>
</Object>
<Object>
<Key>Key-ABCD</Key>
</Object>
</Objects>
</child>
and creates some html output that looks like this.
<table border=1>
<tr>
<td>
Key
</td>
<td>
Key-1234
</td>
<tr>
</tr>
<td colspan="2">
Source-A
</td>
</tr>
<tr>
<td>
Key
</td>
<td>
Key-5678
</td>
<tr>
</tr>
<td colspan="2">
Source-A
Source-B
</td>
</tr>
<tr>
<td>
Key
</td>
<td>
Key-ABCD
</td>
<tr>
</tr>
<td colspan="2">
Source-B
</td>
</tr>
</table>
Here is what I have so far, but I'm not sure it's even possible, any hints on how to do it? Or am I trying to do something thats not possible?
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="/">
<html>
<!--<xsl:variable name="keyMap" />-->
<xsl:variable name="keyMap">
<xsl:for-each select="root/children/child">
<xsl:variable name="object" select="."/>
<!--<xsl:value-of select="$object"/>-->
<xsl:for-each select="document(concat(translate($object,' ',''),'.xml'))/child/Objects/Object">
<xsl:value-of 开发者_开发技巧select="Key"/>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="$keyMap"/>
</html>
</xsl:template>
</xsl:stylesheet>
Update: Two phase transformation with node-set()
extension function.
This stylesheet:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:key name="kKeyByValue" match="Key" use="."/>
<xsl:template match="/">
<xsl:variable name="vFirstPass">
<xsl:for-each select="root/children/child">
<xsl:variable name="vSource" select="normalize-space()"/>
<source href="{$vSource}">
<xsl:copy-of select="document(concat($vSource,'.xml'))
/child/Objects/Object/Key"/>
</source>
</xsl:for-each>
</xsl:variable>
<table border="1">
<xsl:apply-templates select="msxsl:node-set($vFirstPass)/*"/>
</table>
</xsl:template>
<xsl:template match="text()"/>
<xsl:template match="Key[count(.|key('kKeyByValue',.)[1]) = 1]">
<tr>
<td>Key</td>
<td>
<xsl:value-of select="."/>
</td>
</tr>
<tr>
<td colspan="2">
<xsl:for-each select="key('kKeyByValue',.)">
<xsl:value-of select="normalize-space(../@href)"/>
<xsl:if test="position()!=last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
Output:
<table border="1">
<tr>
<td>Key</td>
<td>Key-1234</td>
</tr>
<tr>
<td colspan="2">Source-A</td>
</tr>
<tr>
<td>Key</td>
<td>Key-5678</td>
</tr>
<tr>
<td colspan="2">Source-A Source-B</td>
</tr>
<tr>
<td>Key</td>
<td>Key-ABCD</td>
</tr>
<tr>
<td colspan="2">Source-B</td>
</tr>
</table>
Without extensions, this stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kChildByDocument"
match="child"
use="generate-id(
document(concat(normalize-space(),'.xml'),.)
)"/>
<xsl:key name="kRootByKeys"
match="/"
use="child/Objects/Object/Key"/>
<xsl:variable name="vSource" select="/"/>
<xsl:template match="/" name="getDocuments">
<xsl:param name="pDocuments" select="/.."/>
<xsl:param name="pURIs" select="root/children/child"/>
<xsl:choose>
<xsl:when test="$pURIs">
<xsl:call-template name="getDocuments">
<xsl:with-param name="pDocuments"
select="$pDocuments |
document(concat(normalize-space($pURIs[1]),
'.xml'),
.)"/>
<xsl:with-param name="pURIs"
select="$pURIs[position()>1]"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<table border="1">
<xsl:call-template name="makeRows">
<xsl:with-param name="pDocuments"
select="$pDocuments"/>
</xsl:call-template>
</table>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="makeRows">
<xsl:param name="pDocuments" select="/.."/>
<xsl:param name="pKeys"
select="$pDocuments/child/Objects/Object/Key"/>
<xsl:if test="$pKeys">
<xsl:variable name="vKey" select="$pKeys[1]"/>
<tr>
<td>Key</td>
<td>
<xsl:value-of select="$vKey"/>
</td>
</tr>
<tr>
<td colspan="2">
<xsl:for-each select="$pDocuments[
key('kRootByKeys',$vKey)
]">
<xsl:variable name="vDocument"
select="generate-id()"/>
<xsl:for-each select="$vSource">
<xsl:value-of
select="normalize-space(
key('kChildByDocument',
$vDocument)
)"/>
</xsl:for-each>
<xsl:if test="position()!=last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</td>
</tr>
<xsl:call-template name="makeRows">
<xsl:with-param name="pDocuments" select="$pDocuments"/>
<xsl:with-param name="pKeys" select="$pKeys[.!=$vKey]"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
精彩评论