Xml 在处理XInclude之前,是否可以插入默认的xi:fallback实例?
假设我有一个使用XIncludes的源XML文档,如下所示:Xml 在处理XInclude之前,是否可以插入默认的xi:fallback实例?,xml,xslt,xslt-2.0,xinclude,Xml,Xslt,Xslt 2.0,Xinclude,假设我有一个使用XIncludes的源XML文档,如下所示: <?xml version="1.0" encoding="UTF-8"?> <parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01"> <xi:include href="child01.xml"/> <xi:include href="child02.xml"/> <xi:incl
<?xml version="1.0" encoding="UTF-8"?>
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01">
<xi:include href="child01.xml"/>
<xi:include href="child02.xml"/>
<xi:include href="child03.xml"/>
</parent>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="parent"/>
</xsl:template>
<xsl:template match="parent">
<volume>
<xsl:apply-templates select="@*|.//child"/>
</volume>
</xsl:template>
<xsl:template match="child">
<chapter>
<xsl:apply-templates select="@*|*|text()"/>
</chapter>
</xsl:template>
<xsl:template match="@*|*|text()">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="@*|*|text()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01">
<xi:include href="child01.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
<xi:include href="child02.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
<xi:include href="child03.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
</parent>
它在XIncludes中调用的另外三个XML文档如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01">
<xi:include href="child01.xml"/>
<xi:include href="child02.xml"/>
<xi:include href="child03.xml"/>
</parent>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="parent"/>
</xsl:template>
<xsl:template match="parent">
<volume>
<xsl:apply-templates select="@*|.//child"/>
</volume>
</xsl:template>
<xsl:template match="child">
<chapter>
<xsl:apply-templates select="@*|*|text()"/>
</chapter>
</xsl:template>
<xsl:template match="@*|*|text()">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="@*|*|text()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01">
<xi:include href="child01.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
<xi:include href="child02.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
<xi:include href="child03.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
</parent>
child01.xml:
<?xml version="1.0" encoding="UTF-8"?>
<children>
<child xml:id="child01">
<p>This is child 1.</p>
</child>
</children>
这是儿童1
child02.xml:
<?xml version="1.0" encoding="UTF-8"?>
<children>
<child xml:id="child02">
<p>This is child 2.</p>
</child>
</children>
这是儿童2
child03.xml:
<?xml version="1.0" encoding="UTF-8"?>
<children>
<child xml:id="child03">
<p>This is child 3.</p>
</child>
</children>
这是孩子3
我有一个XSLT 2.0转换,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01">
<xi:include href="child01.xml"/>
<xi:include href="child02.xml"/>
<xi:include href="child03.xml"/>
</parent>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="parent"/>
</xsl:template>
<xsl:template match="parent">
<volume>
<xsl:apply-templates select="@*|.//child"/>
</volume>
</xsl:template>
<xsl:template match="child">
<chapter>
<xsl:apply-templates select="@*|*|text()"/>
</chapter>
</xsl:template>
<xsl:template match="@*|*|text()">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="@*|*|text()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01">
<xi:include href="child01.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
<xi:include href="child02.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
<xi:include href="child03.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
</parent>
当XIncludes引用的所有文件与parent01.xml位于同一文件夹中时,我的转换工作正常,并生成以下输出:
<?xml version="1.0" encoding="UTF-8"?>
<volume xml:id="parent01">
<chapter xml:id="child01">
<p>This is child 1.</p>
</chapter>
<chapter xml:id="child02">
<p>This is child 2.</p>
</chapter>
<chapter xml:id="child03">
<p>This is child 3.</p>
</chapter>
</volume>
这是儿童1
这是儿童2
这是孩子3
但是,如果缺少一个文件(例如child02.xml),转换将失败
如果parent01.xml包含xi:fallback元素,则可以防止此失败,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01">
<xi:include href="child01.xml"/>
<xi:include href="child02.xml"/>
<xi:include href="child03.xml"/>
</parent>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="parent"/>
</xsl:template>
<xsl:template match="parent">
<volume>
<xsl:apply-templates select="@*|.//child"/>
</volume>
</xsl:template>
<xsl:template match="child">
<chapter>
<xsl:apply-templates select="@*|*|text()"/>
</chapter>
</xsl:template>
<xsl:template match="@*|*|text()">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="@*|*|text()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01">
<xi:include href="child01.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
<xi:include href="child02.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
<xi:include href="child03.xml">
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xi:include>
</parent>
文件丢失了
文件丢失了
文件丢失了
然后,输出将如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<volume xml:id="parent01">
<chapter xml:id="child01">
<p>This is child 1.</p>
</chapter>
<chapter>
<p>The file is missing.</p>
</chapter>
<chapter xml:id="child03">
<p>This is child 3.</p>
</chapter>
</volume>
这是儿童1
文件丢失了
这是孩子3
我的问题是:是否可以编写XSLT转换,在处理XInclude之前在每个xi:include中插入xi:fallback实例——也就是说,在不存在xi:fallback实例的情况下添加一个默认xi:fallback实例,然后像处理XInclude一样处理XInclude
感谢任何人提供的建议。将我的评论扩展到完整答案,因为这是一个有趣的问题 XSLT转换不直接对XML文档的文本内容进行操作,而是对内容的树状表示(DOM、XDM)进行操作。输入的这种表示或模型由XML解析器提供,理论上,XML解析器可以完全独立于XSLT处理器 现在重要的一点是:XML解析器负责执行Xinclusion,而不是XSLT处理器。一旦XSLT处理程序看到文档模型,就无法知道是否发生了错误。不,据我所知,在单个XSLT转换步骤中,无法访问XInclude前后的文档树。您可以在不同的模式下处理相同的输入节点两次,但还需要能够从XSLT转换中控制XML解析器的XInclude功能,这是不可能的 我建议您绕道一点,分两步解决问题:编写一个XSLT转换,在不使用XInclude的情况下应用(在XML IDE的XML解析器首选项(如Oxygen)中或在命令行中故意关闭此选项),以修复缺少的回退: 修复回退的XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xi:include[not(xi:fallback)]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XSLT样式表
<?xml version="1.0" encoding="UTF-8"?>
<parent xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="parent01">
<xi:include href="file:/Users/User/Desktop/child01.xml"/>
<xi:include href="file:/Users/User/Desktop/child02.xml"/>
<xi:include href="file:/Users/User/Desktop/child03.xml"/>
</parent>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:xi="http://www.w3.org/2001/XInclude"
exclude-result-prefixes="xi">
<xsl:import href="xipr.xsl"/>
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:variable name="fixedfallbacks">
<xsl:apply-templates select="." mode="fixfallbacks"/>
</xsl:variable>
<xsl:variable name="xincluded">
<xsl:apply-templates select="$fixedfallbacks" mode="xipr"/>
</xsl:variable>
<xsl:apply-templates select="$xincluded/*" mode="#default"/>
</xsl:template>
<xsl:template match="xi:include[not(xi:fallback)]" mode="fixfallbacks">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="fixfallbacks"/>
<xi:fallback>
<child>
<p>The file is missing.</p>
</child>
</xi:fallback>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()" mode="fixfallbacks">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="fixfallbacks"/>
</xsl:copy>
</xsl:template>
<xsl:template match="parent">
<volume>
<xsl:apply-templates select="@*|.//child"/>
</volume>
</xsl:template>
<xsl:template match="child">
<chapter>
<xsl:apply-templates select="@*|*|text()"/>
</chapter>
</xsl:template>
<xsl:template match="@*|*|text()">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="@*|*|text()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<volume xml:id="parent01">
<chapter>
<p>The file is missing.</p>
</chapter>
<chapter xml:id="child02">
<p>This is child 2.</p>
</chapter>
<chapter xml:id="child03">
<p>This is child 3.</p>
</chapter>
</volume>
您使用什么XSLT处理器和XML解析来包含和转换结果?但无论如何,我认为答案是:Xinclutions在XSLT转换看到文档之前完成。XInclude是由XML解析器完成的,它是XSLT处理的上游。非常感谢,Mathias-这是非常有用的信息。我会考虑这两种选择;无论哪种方式,我都需要建立一个组织中其他人可以轻松运行的流程:可能需要仔细配置氧气中的转换场景,并提供清晰的文档。