问题描述
我正在尝试使用xslt和saxon-HE 9.9.1 .NET合并特定文件夹中的多个xml文件。我需要创建一个通用合并,这样我就不会在模板内添加静态标签以将其与不同节点的名称一起使用,我尝试制作一个循环以在开始时一次添加根或顶级标签,但同时在xml结束之前关闭标签,但顶层标签有问题 例: XML File1:
<Arr xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Src>
<name>C</name>
<pr>pr</pr>
<par>
<Q>
<isC>false</isC>
<name>hrh1</name>
<type>xx1</typ>
</Q>
</par>
<st />
</Src>
<Src>
<name>C</name>
<pr></pr>
<par>
<Q>
<isC>false</isC>
<name>hrh2</name>
<type>xx2</typ>
</Q>
</par>
<st>
<Src>
<name>st1</name>
<pr>prst1</pr>
<par>
<Q>
<isC>false</isC>
<name>q1</name>
<type>t1</type>
</Q>
<Q>
<isC>false</isC>
<name>q2</name>
<type>t2</type>
</Q>
</par>
<st />
</Src>
</st>
</Src>
</Arr>
XML File2:
<Arr xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Src>
<name>CFile2</name>
<pr>C2</pr>
<par>
<Q>
<isC>false</isC>
<name>hrh1</name>
<type>xx1</typ>
</Q>
</par>
<st />
</Src>
</Arr>
预期输出:
<Arr xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Src>
<name>C</name>
<pr>pr</pr>
<par>
<Q>
<isC>false</isC>
<name>hrh1</name>
<type>xx1</typ>
</Q>
</par>
<st />
</Src>
<Src>
<name>C</name>
<pr></pr>
<par>
<Q>
<isC>false</isC>
<name>hrh2</name>
<type>xx2</typ>
</Q>
</par>
<st>
<Src>
<name>st1</name>
<pr>prst1</pr>
<par>
<Q>
<isC>false</isC>
<name>q1</name>
<type>t1</type>
</Q>
<Q>
<isC>false</isC>
<name>q2</name>
<type>t2</type>
</Q>
</par>
<st />
</Src>
</st>
</Src>
<Src>
<name>CFile2</name>
<pr>C2</pr>
<par>
<Q>
<isC>false</isC>
<name>hrh1</name>
<type>xx1</typ>
</Q>
</par>
<st />
</Src>
</Arr>
<?xml version="1.0" encoding="windows-1256"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:user="http://tempuri.org/msxsl" >
<xsl:output method="xml" indent="yes" encoding="windows-1256" />
<xsl:template name="main">
<xsl:for-each select="collection('.?select=*.xml')/*">
<xsl:choose>
<xsl:when test="position() = 1">
<xsl:copy>
<xsl:copy-of select="/*/node()"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="/*/node()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
我使用以下命令从cmd运行:
transform -it:main -xsl:merge_xml.xslt -o:output.xml
<Arr xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Src>
<name>C</name>
<pr>pr</pr>
<par>
<Q>
<isC>false</isC>
<name>hrh1</name>
<type>xx1</typ>
</Q>
</par>
<st />
</Src>
<Src>
<name>C</name>
<pr></pr>
<par>
<Q>
<isC>false</isC>
<name>hrh2</name>
<type>xx2</typ>
</Q>
</par>
<st>
<Src>
<name>st1</name>
<pr>prst1</pr>
<par>
<Q>
<isC>false</isC>
<name>q1</name>
<type>t1</type>
</Q>
<Q>
<isC>false</isC>
<name>q2</name>
<type>t2</type>
</Q>
</par>
<st />
</Src>
</st>
</Src>
</Arr>
<Src>
<name>CFile2</name>
<pr>C2</pr>
<par>
<Q>
<isC>false</isC>
<name>hrh1</name>
<type>xx1</typ>
</Q>
</par>
<st />
</Src>
解决方法
我会简单地使用
<xsl:param name="uris" select="uri-collection('.?select=*.xml')"/>
<xsl:template name="xsl:initial-template">
<xsl:copy select="$uris => head() => doc()/*">
<xsl:copy-of select="($uris ! doc(.))/*/node()"/>
</xsl:copy>
</xsl:template>
如果可以尝试使用Saxon EE,则可以切换到流式传输
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all" expand-text="yes">
<xsl:function name="mf:merge" as="document-node()">
<xsl:param name="uris"/>
<xsl:source-document href="{head($uris)}" streamable="yes">
<xsl:document>
<xsl:copy select="*">
<xsl:copy-of select="node()"/>
<xsl:iterate select="tail($uris)">
<xsl:source-document href="{.}" streamable="yes">
<xsl:copy-of select="*/node()"/>
</xsl:source-document>
</xsl:iterate>
</xsl:copy>
</xsl:document>
</xsl:source-document>
</xsl:function>
<xsl:output method="xml" indent="yes"/>
<xsl:template name="xsl:initial-template">
<xsl:sequence select="mf:merge(uri-collection('?select=*.xml'))"/>
</xsl:template>
</xsl:stylesheet>
,
马丁的解决方案可以工作,但我可以:
<xsl:template name="xsl:initial-template">
<xsl:variable name="coll" select="collection('.?select=*.xml')"/>
<xsl:copy select="$coll[1]/*">
<xsl:copy-of select="$coll/*/*"/>
</xsl:copy>
</xsl:template>