gpt4 book ai didi

XSLT 身份转换产生错误的命名空间

转载 作者:行者123 更新时间:2023-12-04 16:51:06 33 4
gpt4 key购买 nike

我有一个正在发展的自定义 XML 模式:添加元素,删除其他元素,命名空间更改以反射(reflect)新版本(例如,从“http://foo/1.0”到“http://foo/1.1”) .我想编写一个 XSLT,将 XML 文档从旧模式转换为新模式。我的第一次尝试有效,但它冗长且不可扩展,我需要帮助改进它。

这是 1.0 模式的示例文档:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo:rootElement xmlns:foo="http://foo/1.0">
<obsolete>something</obsolete>
<stuff>
<alpha>a</alpha>
<beta>b</beta>
</stuff>
</foo:rootElement>

在 1.1 模式中,“过时”元素消失了,但其他所有内容都保留了下来。所以 XSLT 需要做两件事:
  • 移除标签
  • 将 namespace 从 http://foo/1.0 更改为至 http://foo/1.1

  • 这是我的解决方案:
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:foo1="http://foo/1.0"
    xmlns:foo="http://foo/1.1"
    exclude-result-prefixes="foo1">

    <xsl:output method="xml" standalone="yes" indent="yes"/>

    <!-- Remove the "obsolete" tag -->
    <xsl:template match="foo1:rootElement/obsolete"/>

    <!-- Copy the "alpha" tag -->
    <xsl:template match="foo1:rootElement/stuff/alpha">
    <alpha>
    <xsl:apply-templates/>
    </alpha>
    </xsl:template>

    <!-- Copy the "beta" tag -->
    <xsl:template match="foo1:rootElement/stuff/beta">
    <beta>
    <xsl:apply-templates/>
    </beta>
    </xsl:template>

    <!-- Copy the "stuff" tag -->
    <xsl:template match="foo1:rootElement/stuff">
    <stuff>
    <xsl:apply-templates/>
    </stuff>
    </xsl:template>

    <!-- Copy the "rootElement" tag -->
    <xsl:template match="foo1:rootElement">
    <foo:rootElement>
    <xsl:apply-templates/>
    </foo:rootElement>
    </xsl:template>

    </xsl:stylesheet>

    尽管这会产生我想要的输出,但请注意,我为模式中的每个元素都有一个复制模板:alpha、beta 等。对于具有数百种元素的复杂模式,我必须添加数百个模板!

    我想我可以通过将所有这些复制模板减少到一个单一的身份转换来消除这个问题,如下所示:
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:foo1="http://foo/1.0"
    xmlns:foo="http://foo/1.1"
    exclude-result-prefixes="foo1">

    <xsl:output method="xml" standalone="yes" indent="yes"/>

    <xsl:template match="foo1:rootElement/obsolete"/>

    <xsl:template match="node()|@*" name="identity">
    <xsl:copy>
    <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
    </xsl:template>

    <xsl:template match="foo1:rootElement/stuff">
    <xsl:copy>
    <xsl:call-template name="identity"/>
    </xsl:copy>
    </xsl:template>

    <xsl:template match="foo1:rootElement">
    <foo:rootElement>
    <xsl:apply-templates/>
    </foo:rootElement>
    </xsl:template>

    </xsl:stylesheet>

    但它产生:
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <foo:rootElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:foo="http://foo/1.1">
    <stuff xmlns:foo="http://foo/1.0">
    <stuff>
    <alpha>a</alpha>
    <beta>b</beta>
    </stuff>
    </stuff>
    </foo:rootElement>

    “stuff”元素被复制,这正是我想要的,但它被包装在另一个“stuff”元素中,用旧的命名空间标记。我不明白为什么会这样。我尝试了很多方法来解决这个问题,但都没有成功。有什么建议?谢谢。

    最佳答案

    本次改造 :

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="pOldNS" select="'http://foo/1.0'"/>
    <xsl:param name="pNewNS" select="'http://foo/1.1'"/>

    <xsl:template match="/*">
    <xsl:element name="{name()}" namespace="{$pNewNS}">
    <xsl:apply-templates select="node()|@*"/>
    </xsl:element>
    </xsl:template>

    <xsl:template match="*">
    <xsl:element name="{name()}">
    <xsl:copy-of select="namespace::*[not(.=$pOldNS)]"/>

    <xsl:apply-templates select="node()|@*"/>
    </xsl:element>
    </xsl:template>

    <xsl:template match="@*">
    <xsl:choose>
    <xsl:when test="namespace-uri()=$pOldNS">
    <xsl:attribute name="{name()}" namespace="{$pNewNS}">
    <xsl:value-of select="."/>
    </xsl:attribute>
    </xsl:when>
    <xsl:otherwise>
    <xsl:copy-of select="."/>
    </xsl:otherwise>
    </xsl:choose>
    </xsl:template>

    <xsl:template match="obsolete"/>
    </xsl:stylesheet>

    应用于此 XML 文档时 :
    <foo:rootElement xmlns:foo="http://foo/1.0">
    <obsolete>something</obsolete>
    <stuff>
    <alpha x="y" foo:t="z">a</alpha>
    <beta>b</beta>
    </stuff>
    </foo:rootElement>

    产生想要的、正确的结果 ( obsolute 元素删除,命名空间升级,属性节点正确处理,包括旧命名空间中的节点):
    <foo:rootElement xmlns:foo="http://foo/1.1">
    <stuff>
    <alpha x="y" foo:t="z">a</alpha>
    <beta>b</beta>
    </stuff>
    </foo:rootElement>

    此解决方案的主要优点 :
  • 当存在属于旧模式命名空间的属性时正常工作 .
  • 一般,允许新旧命名空间作为外部参数传递到转型。
  • 关于XSLT 身份转换产生错误的命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5929756/

    33 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com