XSLT 替换命名空间并添加新的(未使用的)命名空间
Posted
技术标签:
【中文标题】XSLT 替换命名空间并添加新的(未使用的)命名空间【英文标题】:XSLT to replace a namespace and also add a new (unused) namespace 【发布时间】:2021-05-17 20:11:31 【问题描述】:我想替换以下 XML 文档的命名空间
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Document xmlns:ns0="http://mydata.com/H2H/Automation">
<CstmrCdtTrfInitn>
<GrpHdr>
</GrpHdr>
</CstmrCdtTrfInitn>
</ns0:Document>
以下
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CstmrCdtTrfInitn>
<GrpHdr>
</GrpHdr>
</CstmrCdtTrfInitn>
</Document>
关于可以转换它的 XSLT 有什么想法吗?
我尝试了以下 XSL,但它正在添加带有第二个节点的命名空间,并且也无法删除第一个命名空间。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="UTF-8" indent="yes"/>
<xsl:template match="/*">
<xsl:element name="local-name()" namespace="http://www.w3.org/2001/XMLSchema-instance">
<xsl:copy-of select="./*" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
【问题讨论】:
你到底在哪里坚持这个? 不知道如何编写 XSLT 来删除旧名称并添加两个新名称空间 【参考方案1】:您的要求可能有点棘手:替换 Document
元素的默认命名空间很简单。但是在 XSLT-1.0 中添加未使用的 xslns:xsi
命名空间需要 EXSLT 扩展和 Michael Kay 在回复 this question 时解释的特殊技术。它涉及在全局变量中创建一个未使用的元素,然后将其命名空间复制到模板中以替换默认命名空间。在 XSLT-2.0 及更高版本中,这会更容易(见下文)。
EXSLT 扩展并非在所有 XSLT-1.0 处理器中都可用。但是有必要从变量中创建一个节点集。
所以所有的命名空间都要在xsl:stylesheet
元素中定义,然后根元素(这里是ns0:Document
)被一个模板匹配并替换为它的local-name()
部分,添加了新的默认命名空间,然后是复制变量中定义的元素的“虚拟”命名空间。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://mydata.com/H2H/Automation" xmlns:urn="urn:iso:std:iso" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ext="http://exslt.org/common">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<!-- identity template (except elements)-->
<xsl:template match="node()[not(self::*)]|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:variable name="nsXSI">
<xsl:element name="xsi:dummy" namespace="http://www.w3.org/2001/XMLSchema-instance" />
</xsl:variable>
<xsl:template match="ns0:*|*">
<xsl:element name="local-name()" namespace="urn:iso:std:iso">
<xsl:copy-of select="ext:node-set($nsXSI)/*/namespace::xsi" />
<xsl:apply-templates select="node() | @*" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
即使在 XSLT-1.0 中,输出也应该符合预期:
<Document xmlns="urn:iso:std:iso" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CstmrCdtTrfInitn>
<GrpHdr>
</GrpHdr>
</CstmrCdtTrfInitn>
</Document>
简化的解决方案需要支持 XSLT-2.0 的处理器。然后你可以使用xsl:namespace指令如下,不需要“虚拟”变量:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://mydata.com/H2H/Automation">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<!-- identity template (except elements)-->
<xsl:template match="node()[not(self::element())]|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="ns0:*|*">
<xsl:element name="local-name(.)" namespace="urn:iso:std:iso">
<xsl:namespace name="xsi">http://www.w3.org/2001/XMLSchema-instance</xsl:namespace>
<xsl:apply-templates select="node() | @*" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
输出是一样的。
通过使用 XSLT-3.0+ 的 xsl:mode
将 身份模板 替换为
<xsl:mode on-no-match="shallow-copy"/>
【讨论】:
感谢您的快速回复。它给了我错误 sapxiapping:nsfinal.xsl: line 6: Error parsing XPath expression 'node()[not(self::element())]|@*' 你是对的。我必须添加一个名为 EXSLT 的外部库以使 XSLT-1.0 答案工作并将element()
更改为*
。
抱歉没有得到,我是否应该更改上述解决方案中的任何内容。
是的。我更改了 XSLT。您还需要 EXSLT 扩展来使用 XSLT-1.0 解决方案。如果你没有它,你会被 XSLT-2.0 或更高版本卡住。
感谢修改版本在一定程度上起作用,但它添加了 urn:iso:std:iso 与所有父节点 ns1 ns2 ns3【参考方案2】:
你有什么理由不能简单地做:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://mydata.com/H2H/Automation"
exclude-result-prefixes="ns0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:element name="local-name()" namespace="urn:iso:std:iso">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="/ns0:Document">
<Document xmlns="urn:iso:std:iso" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:apply-templates/>
</Document>
</xsl:template>
</xsl:stylesheet>
【讨论】:
以上是关于XSLT 替换命名空间并添加新的(未使用的)命名空间的主要内容,如果未能解决你的问题,请参考以下文章
xsd:any 元素的命名空间前缀并使用 XSLT 添加命名空间前缀