如果我有这个文件: 输入file1.xml:
<schema>
<sequence>
<nodeA id="a">
<fruit id="small">
<orange id="x" method="create">
<attributes>
<color>Orange</color>
<year>2000</year>
</attributes>
</orange>
</fruit>
<fruit id="small">
<apple id="x" method="create">
<attributes>
<color>Orange</color>
<year>2000</year>
</attributes>
</apple>
</fruit>
<fruit id="medium">
<orange id="x" method="create">
<attributes>
<color>Orange</color>
<year>2000</year>
</attributes>
</orange>
</fruit>
</nodeA>
<nodeB id="b">
<dog id="large">
<doberman id="x" method="create">
<condition>
<color>Black</color>
</condition>
</doberman>
</dog>
</nodeB>
</sequence>
</schema>
file2.xml:
<schema>
<sequence>
<nodeA id="a">
<fruit id="small">
<melon id="x" method="create">
<attributes>
<color>Orange</color>
<year>2000</year>
</attributes>
</melon>
</fruit>
</nodeA>
<nodeB id="b">
<dog id="small">
<poodle id="x" method="create">
<condition>
<color>White</color>
</condition>
</poodle>
</dog>
</nodeB>
</sequence>
</schema>
连接后: 输出:concate.xml
<schema>
<sequence>
<nodeA id="a">
<fruit id="small">
<orange id="x" method="create">
<attributes>
<color>Orange</color>
<year>2000</year>
</attributes>
</orange>
</fruit>
<fruit id="small">
<apple id="x" method="create">
<attributes>
<color>Orange</color>
<year>2000</year>
</attributes>
</apple>
</fruit>
<fruit id="medium">
<orange id="x" method="create">
<attributes>
<color>Orange</color>
<year>2000</year>
</attributes>
</orange>
</fruit>
<fruit id="small">
<melon id="x" method="create">
<attributes>
<color>Orange</color>
<year>2000</year>
</attributes>
</melon>
</fruit>
</nodeA>
<nodeB id="b">
<dog id="large">
<doberman id="x" method="create">
<condition>
<color>Black</color>
</condition>
</doberman>
</dog>
<dog id="small">
<poodle id="x" method="create">
<condition>
<color>White</color>
</condition>
</poodle>
</dog>
</nodeB>
</sequence>
</schema>
对于concate,它将依赖于文件顺序,因此file2.xml中的节点将放在file1.xml的节点下(如示例所示)。我最多有5个文件。 如何仅使用xsl转换实现这一点,即xslt将同时输入5个文件并输出1个文件?
这是文档结构和合并点:
<schema>
<sequence>
<nodeA id="a">
<fruit id="small">
<orange id="x" method="create">
...
</orange>
</fruit>
<fruit id="small">
...
</fruit>
<fruit id="large">
...
</fruit>
<!-- we merge below this -->
</nodeA>
<nodeB id="b">
<dog id="large">
<doberman id="x" method="create">
...
</doberman>
</dog>
<dog id="small">
<doberman id="x" method="create">
...
</doberman>
</dog>
<!-- we merge below this -->
</nodeB>
<somenode id="any">
...
</somenode>
</sequence>
</schema>
注意:如果不可能连接只有两个文件输入将是正常的,因为它可以始终重复其他文件。 此外,文件中还有各种节点名称(nodeA,nodeB,SomeNode等),因此需要能够推广此问题。
我们可以使用xsl1.0或2.0。
非常感谢。 约翰
答案 0 :(得分:3)
@John,这是一个更通用的解决方案:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:a="http://a.com">
<xsl:strip-space elements="*" />
<xsl:output indent="yes" method="xml" />
<xsl:variable name="to-merge" select="document('input2.xml') | document('input3.xml')"/>
<xsl:function name="a:id">
<xsl:param name="ctx"/>
<xsl:value-of select="concat($ctx/local-name(), $ctx/@id)"/>
</xsl:function>
<xsl:key name="match" match="/schema/sequence/*" use="a:id(.)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[count(. | key('match', a:id(.))) = count(key('match', a:id(.)))]">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
<xsl:variable name="id" select="a:id(.)"/>
<xsl:for-each select="$to-merge">
<xsl:apply-templates select="key('match', $id)/*"/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
您可以在key
中定义合并点,并在a:id
中定义合并匹配功能。只需将a:id
函数放入谓词中即可回退到XSLT 1.0。
我的假设:
to-merge
变量local-name()
和@id
答案 1 :(得分:1)
这是另一个答案。这加入了schema / sequence / *级别,而不仅仅是nodeA和NodeB。
<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0"
exclude-result-prefixes="xsl xs fn">
<xsl:output indent="yes" encoding="UTF-8" />
<xsl:param name="file2" /> <!-- input file1.xml -->
<xsl:variable name="file1-doc" select="root()" />
<xsl:variable name="file2-doc" select="document($file2)" />
<xsl:template match="/">
<schema>
<sequence>
<xsl:call-template name="union-point">
<xsl:with-param name="value" select="schema/sequence/*"/>
</xsl:call-template>
<xsl:call-template name="union-point">
<!-- The following predicate excludes all the node names that we
have already processed in the first call-template. -->
<xsl:with-param name="value" select="$file2-doc/schema/sequence/*
[not (fn:exists($file1-doc/schema/sequence/name()))]
"/>
</xsl:call-template>
</sequence>
</schema>
</xsl:template>
<xsl:template name="union-point">
<xsl:param name="value"/>
<xsl:for-each select="$value/name()" >
<xsl:variable name="node-name" select="."/>
<xsl:element name="{.}">
<xsl:attribute name="id">
<xsl:value-of select="($file1-doc/schema/sequence/*[name()=$node-name]/@id |
$file2-doc/schema/sequence/*[name()=$node-name]/@id )[1]" />
</xsl:attribute>
<xsl:apply-templates select="$file1-doc/schema/sequence/*[name()=$node-name]/*" />
<xsl:apply-templates select="$file2-doc/schema/sequence/*[name()=$node-name]/*" />
</xsl:element>
</xsl:for-each>
</xsl:template>
<xsl:template match="element()">
<xsl:copy>
<xsl:apply-templates select="@*,node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="attribute()|text()|comment()|processing-instruction()">
<xsl:copy/>
</xsl:template>
</xsl:stylesheet>
作为一种解决方案,它可能有点笨拙和笨拙,但它基本上有效。希望像Dimitre Novatchev这样的专家能够出现并提供更整洁的选择。这是我能力的极限。
* 更新1 * 我将id属性添加到了等等。
更新2 以下是结果输出:
<?xml version="1.0" encoding="UTF-8"?>
<schema>
<sequence>
<nodeA id="a">
<fruit id="small">
<orange id="x" method="create">
<attributes>
<color>Orange</color>
<year>2000</year>
</attributes>
</orange>
</fruit>
<fruit id="small">
<apple id="x" method="create">
<attributes>
<color>Orange</color>
<year>2000</year>
</attributes>
</apple>
</fruit>
<fruit id="medium">
<orange id="x" method="create">
<attributes>
<color>Orange</color>
<year>2000</year>
</attributes>
</orange>
</fruit>
<fruit id="small">
<melon id="x" method="create">
<attributes>
<color>Orange</color>
<year>2000</year>
</attributes>
</melon>
</fruit>
</nodeA>
<nodeB id="b">
<dog id="large">
<doberman id="x" method="create">
<condition>
<color>Black</color>
</condition>
</doberman>
</dog>
<dog id="small">
<poodle id="x" method="create">
<condition>
<color>White</color>
</condition>
</poodle>
</dog>
</nodeB>
</sequence>
</schema>
答案 2 :(得分:0)
尝试:
<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0"
exclude-result-prefixes="xsl xs fn">
<xsl:output indent="yes" encoding="UTF-8" />
<xsl:param name="file2" /> <!-- input file1.xml -->
<xsl:variable name="file2-doc" select="document($file2)" />
<xsl:template match="/">
<schema>
<sequence>
<nodeA id="a">
<xsl:apply-templates select="schema/sequence/nodeA/*" />
<xsl:apply-templates select="$file2-doc/schema/sequence/nodeA/*" />
</nodeA>
<nodeB id="b">
<xsl:apply-templates select="schema/sequence/nodeB/*" />
<xsl:apply-templates select="$file2-doc/schema/sequence/nodeB/*" />
</nodeB>
</sequence>
</schema>
</xsl:template>
<xsl:template match="element()">
<xsl:copy>
<xsl:apply-templates select="@*,node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="attribute()|text()|comment()|processing-instruction()">
<xsl:copy/>
</xsl:template>
</xsl:stylesheet>
将file1设为主文档输入。将file2的文件名作为参数“file2”传递。类似地扩展多个输入文件。