我正在编写一个XSLT转换,我希望在根元素上定义所有名称空间前缀。默认情况下,MS似乎在XML层次结构的第一个元素上创建一个新的前缀定义来使用该模式;意味着如果这些元素与同一模式的共享祖先无关,则可以在多个元素上引用相同的模式。
通过对根元素进行编码,所有工作都可以正常工作:
<!-- ... -->
<ns0:root xmlns:ns0="http://some/schema" xmlns:ns1 = "http://another/schema">
<!-- rest of XSLT; including calls to other templates -->
</ns0:root>
<!-- ... -->
但是我找不到使用xsl:element
对此进行编码的方法; e.g。
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://some/schema"
xmlns:ns1 = "http://another/schema"
>
<!-- ... -->
<xsl:element name="ns0:root">
<xsl:attribute name="ns1" namespace="http://www.w3.org/2000/xslns/">http://another/schema</xsl:attribute>
<!-- rest of XSLT; including calls to other templates -->
</xsl:element>
<!-- ... -->
对于除该元素本身以外的模式,是否可以针对xls:element
声明名称空间前缀?
XML
<Demo xmlns="http://some/schema">
<a>Hello</a>
<b>World</b>
</Demo>
XSLT
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://some/schema"
xmlns:ns1 = "http://another/schema"
exclude-result-prefixes="xsl"
>
<xsl:output method="xml" indent="yes" version="1.0"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
<xsl:apply-templates select="@* | node()" />
</xsl:element>
</xsl:template>
<xsl:template match="/ns0:Demo/ns0:a">
<xsl:element name="ns1:z">
<xsl:value-of select="./text()" />
</xsl:element>
</xsl:template>
<xsl:template match="/ns0:Demo/ns0:b">
<xsl:element name="ns1:y">
<xsl:value-of select="./text()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
结果
<Demo xmlns="http://some/schema">
<ns1:z xmlns:ns1="http://another/schema">Hello</ns1:z>
<ns1:y xmlns:ns1="http://another/schema">World</ns1:y>
</Demo>
期望的结果
<Demo xmlns="http://some/schema" xmlns:ns1="http://another/schema">
<ns1:z>Hello</ns1:z>
<ns1:y>World</ns1:y>
</Demo>
或
<ns0:Demo xmlns:ns0="http://some/schema" xmlns:ns1="http://another/schema">
<ns1:z>Hello</ns1:z>
<ns1:y>World</ns1:y>
</ns0:Demo>
答案 0 :(得分:2)
您的最小示例没有解释为什么您需要使用xsl:element
而不是xsl:copy
和/或文字结果元素,但因为XSLT 1.0没有xsl:namespace
指令({{3}您唯一的方法是从样式表根目录复制命名空间节点,如
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://some/schema"
xmlns:ns1 = "http://another/schema"
exclude-result-prefixes="xsl"
>
<xsl:output method="xml" indent="yes" version="1.0"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
<xsl:copy-of select="document('')/*/namespace::*[. = 'http://another/schema']"/>
<xsl:apply-templates select="@* | node()" />
</xsl:element>
</xsl:template>
<xsl:template match="/ns0:Demo/ns0:a">
<xsl:element name="ns1:z">
<xsl:value-of select="./text()" />
</xsl:element>
</xsl:template>
<xsl:template match="/ns0:Demo/ns0:b">
<xsl:element name="ns1:y">
<xsl:value-of select="./text()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
(或具有该参数或变量的任何其他节点,但这样您还可以将结果树片段转换为首先使用exsl:node-set
或ms:node-set
设置的节点。
至于为什么文字结果元素和xsl:element
会给你不同的结果,https://www.w3.org/TR/xslt20/#creating-namespace-nodes说:
创建的元素节点还将具有命名空间节点的副本 在样式表树中的元素节点上出现...
答案 1 :(得分:1)
重要的是要理解虽然它们通过名称空间声明属性在XML文档中表示,但在XPath和XSLT的数据模型中,每个元素的范围内命名空间都是通过命名空间节点而不是属性节点建模的。而且,不同的元素不共享命名空间节点;每个人都有自己的一套。使用XML输出方法时,XSLT处理器负责生成名称空间声明属性,这些属性正确表示结果树中存在的名称空间节点。
这完全解释了为什么Section 7.1.3 of the XSLT 1.0 spec明确禁止通过var filePath = await DependencyService.Get<IMediaPicker>().ChooseAFileAsync();
System.Diagnostics.Debug.WriteLine(filePath);
元素创建名称空间声明:
XSLT处理器可以使用QName的前缀 选择用于的前缀时,在name属性中指定 将创建的属性输出为XML;但是,他们不是 要求这样做,如果前缀是
xsl:attribute
,则不得这样做。 因此,虽然这不是一个错误:xmlns
它不会导致输出名称空间声明。
(强调补充。)如果以允许的方式创建名称空间声明,那么它将允许结果文档表示实际上不存在于结果树中的名称空间节点。
结果树中的元素可以通过以下任何方式获取命名空间节点:
<xsl:attribute name="xmlns:xsl" namespace="whatever">http://www.w3.org/1999/XSL/Transform</xsl:attribute>
或xsl:copy
创建的结果元素接收原始元素命名空间节点的副本。xsl:copy-of
样式表元素创建的结果元素未明确指定接收任何命名空间节点,但实际上,要正确实现接收命名空间的命名空间节点所需的规范(如果有的话)元素的名称。没有理由期望XSLT处理器在结果树中创建额外的命名空间节点。特别是,虽然这可能提供结果树更简单的XML序列化的可能性,但树本身将严格地更复杂。
然后,一种方法是确保结果文档中的xsl:element
元素包含除该元素之外的命名空间的命名空间声明,通过从输入树复制结果元素获得的任何元数据,或者元素的一个属性,是使用文字结果元素:
<Demo>
另一方面,如果必须通过<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://some/schema"
xmlns:ns1 = "http://another/schema">
<xsl:output method="xml" indent="yes" version="1.0"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/ns0:Demo">
<ns0:Demo>
<xsl:apply-templates select="@* | node()" />
<ns0:Demo>
</xsl:template>
<!-- ... -->
</xsl:stylesheet>
元素创建元素 - 只有在需要计算其名称时才需要 - 那么您需要从中复制命名空间节点输入树。