雏菊链接Saxon中的XSLT以在第二次传递之前从有效XML中删除CDATA

时间:2014-04-29 14:42:40

标签: xml xslt cdata saxon

我遇到了一个有趣的问题,我试图按顺序菊花链式连接两个转换(使用XSLT 2.0),在第一次传递中从原始XML中删除CDATA元素,以便可以将其解析为XML第二。虽然我怀疑它会影响结果,但我使用Saxon 9 HE中的初始模板参数和collection()函数将多个XML文档(相同的名称空间)收集到变量中,然后再进行转换。值得注意的是,我现在甚至无法使用一个文档。

我的输入文件:

<root>
    <blah>
        <![CDATA[<elementA att="A"><elementB att="B">Text</elementB></elementA>]]>
    </blah>
</root>

我的XSLT尝试:

    <!-- Collect all XML files in $input folder for processing -->
    <xsl:variable name="xml" select="collection(concat($input,'?select=*.*ml;recurse=no;on-error=ignore'))"/>

    <!-- Initial template is called from the saxon command line using the -it:process option -->
    <xsl:template name="process">
        <!-- First pass -->
        <xsl:variable name="pass1xml">
            <xsl:apply-templates select="$xml" mode="pass1"/>
        </xsl:variable>
        <!-- First pass output -->
        <xsl:result-document href="{concat($output,'\pass1.xml')}" method="xml" indent="yes">
            <xsl:copy-of select="$pass1xml"/>
        </xsl:result-document>
        <!-- Second pass -->
        <xsl:apply-templates select="$pass1xml" mode="pass2"/>
    </xsl:template>

    <!-- First pass: copy everything -->
    <xsl:template match="@* | node()" mode="pass1">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" mode="pass1"/>
        </xsl:copy>
    </xsl:template>

    <!-- First pass: strip CDATA from element -->
    <xsl:template match="blah" mode="pass1">
        <xsl:copy>
            <xsl:value-of select="." disable-output-escaping="yes"/>
        </xsl:copy>
    </xsl:template>

    <!-- Second pass using $pass1xml variable -->
    <xsl:template match="root" mode="pass2">
        <!-- Second pass output -->
        <xsl:result-document href="{concat($output,'\pass2.xml')}" method="xml" indent="yes">
            <xsl:apply-templates select="descendant::elementA" mode="elementA"/>
        </xsl:result-document>      
    </xsl:template>

...etc (continue with second pass)...

第一遍的期望输出:

<root>
    <blah>
        <elementA att="A">
            <elementB att="B">Text</elementB>
        </elementA>
    </blah>
</root>

我目前在pass1.xml中看到的内容(第一次传递的结果 - 尽管使用了disable-output-escaping =“yes”)是转义的XML,显然在pass2中不是XPATHable:

<root>
    <blah>
        &lt;elementA att="A"&gt;&lt;elementB att="B"&gt;Text&lt;/elementB&gt;&lt;/elementA&gt;
    </blah>
</root>

不幸的是我无法更改我的源文档以删除CDATA(我很欣赏这会解决我的问题)。 CDATA中的XML也将始终格式良好,因此我毫不犹豫地将其剥离出来。也许我误解了菊花链方法,这意味着我想要达到的目标是不可能的 - 无论如何我都渴望学习。

非常感谢您的时间和建议 - 非常感谢!

1 个答案:

答案 0 :(得分:2)

disable-output-escaping是一个串行功能,所以它对你想要传递到同一样式表中的第二个转换步骤的内存节点没有帮​​助,你需要使用两个样式表,其中第一个的结果在被送到第二个之前先被序列化。

当你提到Saxon时,我会考虑使用商业版本和扩展函数或者提供的[parse-xml][1][parse-xml-fragment][2]等XSLT / XPath 3.0函数来简单地解析和处理例如

<xsl:template match="blah">
  <xsl:apply-templates select="parse-xml-fragment(.)/node()"/>
</xsl:template> 

作为替代方案,在Saxon 9.1 B中,即使在开源版本中也可以使用扩展功能。