我有xml文档,这些文档遵循一个模式,其中大多数已定义的元素都被允许作为有效实例的根。我还有几个xslt的v2.0,它以各种方式翻译它(把它变成普通形式,一个紧凑的形式,一个不同的方言,......)这些xslt都是基于身份变换,添加了模板以实现所需修改。问题在于命名空间属性的增加,因为有些元素来自默认命名空间之外。
我已经尝试了在根元素上插入命名空间的推荐过程,但我似乎无法做到正确。问题是: 1.转换可能会改变名称,有时也会改变根元素的内容,所以我仍然需要每个全局元素的模板,因为我不知道哪个是root,我不能只是插入必要时的名称空间元素(我不知道特定文档需要它们的位置。 2.我想把它实现为多遍,或者只是一个独立的xslt,因为我想要几个不同的xslts相同的结果。在这种情况下,我需要的是一个标识转换,它从文档中的所有元素中获取所有名称空间和前缀,并将它们插入到根目录中。我希望,这会自动从子节点中删除命名空间属性吗?但是,我尝试了以下
<?xml version="1.0" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template name="start" match="/">
<xsl:copy>
<xsl:for-each select="*">
<xsl:copy>
<xsl:for-each select="descendant::*">
<xsl:call-template name="add-ns">
<xsl:with-param name="ns-namespace">
<xsl:value-of select="namespace-uri()"/>
</xsl:with-param>
<xsl:with-param name="ns-prefix">
<xsl:value-of
select=" prefix-from-QName( QName(namespace-uri(),name()))"/>
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template name="add-ns">
<xsl:param name="ns-prefix" select="'x'"/>
<xsl:param name="ns-namespace" select="'someNamespace'"/>
<xsl:namespace name="{$ns-prefix}" select="$ns-namespace"/>
</xsl:template>
<xsl:template match="node()|@* ">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这适用于元素上出现的所有前缀,但它不会捕获属性的前缀。这是一份测试文件:
<RuleML xmlns="http://www.ruleml.org/0.91/xsd">
<Assert textiri="xy>z">
<Importation xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="abc"
textiri="urn:common-logic:demo1"
xlink:href="http://common-logic.org/x>cl/demos.xml"/>
<a:anything xmlns:a="http://anything.org"
xmlns:xlink="http://www.w3.org/1999/xlink"/>
</Assert>
</RuleML>
我希望它能产生:
<RuleML xmlns="http://www.ruleml.org/0.91/xsd" xmlns:a="http://anything.org" xmlns:xlink="http://www.w3.org/1999/xlink" >
<Assert textiri="xy>z">
<Importation xml:id="abc"
textiri="urn:common-logic:demo1"
xlink:href="http://common-logic.org/x>cl/demos.xml"/>
<a:anything/>
</Assert>
</RuleML>
但我得到了
<RuleML xmlns="http://www.ruleml.org/0.91/xsd" xmlns:a="http://anything.org">
<Assert textiri="xy>z">
<Importation xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="abc"
textiri="urn:common-logic:demo1"
xlink:href="http://common-logic.org/x>cl/demos.xml"/>
<a:anything xmlns:xlink="http://www.w3.org/1999/xlink"/>
</Assert>
</RuleML>
塔拉
答案 0 :(得分:3)
以下是否符合您的要求?
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:template match="@* | node()">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:copy-of select="descendant::*/namespace::*"/>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
使用Saxon 9.3,它似乎可以对您发布的样本执行任务。 但是,如果在不同的默认命名空间中有多个元素,或者在不同的命名空间中有多个元素但使用相同的前缀,我不确定你想要做什么。例如
<root xmlns="http://example.com/ns1">
<foo xmlns="http://example.com/ns2">
<pf:bar xmlns:pf="http://example.com/ns3">
<pf:foobar xmlns:pf="http://example.com/ns4"/>
</pf:bar>
</foo>
</root>
Saxon只报告错误
Error at xsl:copy-of on line 15 of test2011061801Xsl2.xsl:
XTDE0430: Cannot create two namespace nodes with the same prefix mapped to different URIs
(prefix="", URI=http://example.com/ns2, URI=http://example.com/ns1)
in built-in template rule
[编辑] 如果您不希望报告错误,可以尝试实施策略以尽可能地提取命名空间节点,但要避免任何冲突。这可以通过for-each-group来完成,如下面的示例XSLT 2.0:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:template match="@* | text() | processing-instruction() | comment()">
<xsl:copy/>
</xsl:template>
<xsl:template match="*">
<xsl:copy copy-namespaces="no">
<xsl:for-each-group select="descendant-or-self::*/namespace::*" group-by="local-name()">
<xsl:copy-of select="."/>
</xsl:for-each-group>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
输入为
<root xmlns="http://example.com/ns1">
<foo xmlns="http://example.com/ns2">
<pf:bar xmlns:pf="http://example.com/ns3">
<pf:foobar xmlns:pf="http://example.com/ns4"/>
</pf:bar>
</foo>
</root>
Saxon 9.3输出
<?xml version="1.0" encoding="UTF-8"?><root xmlns="http://example.com/ns1" xmlns:pf="http://example.com/ns3">
<foo xmlns="http://example.com/ns2">
<pf:bar>
<pf:foobar xmlns:pf="http://example.com/ns4"/>
</pf:bar>
</foo>
</root>
答案 1 :(得分:0)
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*:RuleML">
<xsl:copy>
<xsl:for-each select="descendant::node()">
<xsl:choose>
<xsl:when test="self::text()"/>
<xsl:otherwise>
<xsl:for-each select="namespace::node()">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:apply-templates select="(node() | @*) except namespace::node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="(node() | @*) except namespace::node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>