XMLStarlet + XInclude + XSLT

此生再无相见时 提交于 2019-12-12 09:47:06

问题


I'd like to include contents of an XML document into another XML document and transform it via xmlstarlet+XSLT. I'm trying to use XInclude. (A newbie to both XInclude and XSLT, I am.) The xmlstarlet, though, won't process the included XML doc, it just leaves the inclusion node there untouched.

File a.xml:

<?xml version="1.0" ?>
<doc xmlns:xi="http://www.w3.org/2001/XInclude">
a
<xi:include href="b.xml" />
b
</doc>

File b.xml:

<?xml version="1.0" ?>
<snippet>
c
</snippet>

The x.xsl "pass-through" template:

<?xml version="1.0" encoding="windows-1250" ?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" />

<xsl:template match="/">
<xsl:copy-of select="."/>
</xsl:template>

</xsl:transform>

The command line to be run:

xmlstarlet tr x.xsl a.xml

And the expected output would be something along the lines of:

<?xml version="1.0" ?>
<doc xmlns:xi="http://www.w3.org/2001/XInclude">
a
<snippet>
c
</snippet>
b
</doc>

Yet, the result I get is:

<?xml version="1.0"?>
<doc xmlns:xi="http://www.w3.org/2001/XInclude">
a
<xi:include href="b.xml"/>
b
</doc>

Now, what am I doing wrong?


回答1:


As npostavs already suggested, xmlstarlet does not XInclude documents by default, you need to explicitly mention this as --xinclude. Then, the result is the one you expected:

$ xml tr --xinclude x.xsl a.xml
<?xml version="1.0"?>
<doc xmlns:xi="http://www.w3.org/2001/XInclude">
a
<snippet>
c
</snippet>
b
</doc>

Except for the xi: namespace declaration, which you cannot eliminate with XSLT 1.0 and a simple <xsl:copy-of select="."/>. If that's an issue, the stylesheet becomes a little more complicated, since copy-namespaces="no" is not available in XSLT 1.0:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" />

<xsl:template match="/">
<xsl:apply-templates select="." mode="copy-no-namespaces"/>
</xsl:template>

<xsl:template match="*" mode="copy-no-namespaces">
    <xsl:element name="{local-name()}" namespace="{namespace-uri()}">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="node()" mode="copy-no-namespaces"/>
    </xsl:element>
</xsl:template>

<xsl:template match="comment()| processing-instruction()" mode="copy-no-namespaces">
    <xsl:copy/>
</xsl:template>

</xsl:stylesheet>

This is the standard approach to mimic copy-namespaces="no" in XSLT 1.0, as described here by Michael Kay. Then, the result will be

$ xml tr --xinclude x.xsl a.xml
<?xml version="1.0"?>
<doc>
a
<snippet>
c
</snippet>
b
</doc>


来源:https://stackoverflow.com/questions/29298507/xmlstarlet-xinclude-xslt

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!