过滤名称空间并将其前缀替换为 XSLT

Filter namespaces and replace their prefixes with XSLT

我如何只保留所需的名称空间 URI(可能未使用)并将它们的所有前缀(基于前缀和 URI 列表)替换为 XSLT (1.0)?前缀和名称空间 URI 的原始组合可能会更改!

输入:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns4:node_0 
xmlns:ns6="http://a.com" 
xmlns:ns5="http://b.com" 
xmlns:ns8="http://c.com" 
xmlns:ns7="http://d.com" 
xmlns:ns2="http://e.com"
xmlns:ns4="http://f.com"
xmlns:ns3="http://g.com">
    <node_1 attr_1="attr_1_val" attr_2="attr_2_val">
        <ns4:node_11>node_11_val</ns4:node_11>
        <ns4:node_12 attr_1="attr_1_val" attr_2="attr_2_val">
            <ns2:node_121>node_121_val</ns2:node_121>
            <ns4:node_122>
                <node_1221>node_1221_val</node_1221>
                <ns3:node_1222>
                    <node_12221 attr_1="attr_1_val">
                        <node_122211>node_122211_val</node_122211>
                    </node_12221>
                </ns3:node_1222>
            </ns4:node_122>
            <node_123>
                <node_1231 attr_1="attr_1_val">
                    <node_12311>node_12311_val</node_12311>
                </node_1231>            
            </node_123>
        </ns4:node_12>
        <ns3:node_13>
            <node_131>
                <ns3:node_1311>node_1311_val</ns3:node_1311>
                <node_1312 attr_1="attr_1_val" attr_2="attr_2_val" attr_3="attr_3_val" attr_4="attr_4_val">
                    <ns3:node_13121/>
                </node_1312>
            </node_131>
        </ns3:node_13>
        <node_14/>
    </node_1>
    <ns4:node_2 attr_1="attr_1_val" attr_2="attr_2_val" attr_3="attr_3_val">
        <ns4:node_21>node_21_val</ns4:node_21>
    </ns4:node_2>
</ns4:node_0>

必需的名称空间 URI 及其前缀:

b_ns="http://b.com" 
e_ns="http://e.com"
f_ns="http://f.com"
g_ns="http://g.com"

所以需要输出:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<f_ns:node_0 
xmlns:b_ns="http://b.com" 
xmlns:e_ns="http://e.com"
xmlns:f_ns="http://f.com"
xmlns:g_ns="http://g.com">
    <node_1 attr_1="attr_1_val" attr_2="attr_2_val">
        <f_ns:node_11>node_11_val</f_ns:node_11>
        <f_ns:node_12 attr_1="attr_1_val" attr_2="attr_2_val">
            <e_ns:node_121>node_121_val</e_ns:node_121>
            <f_ns:node_122>
                <node_1221>node_1221_val</node_1221>
                <g_ns:node_1222>
                    <node_12221 attr_1="attr_1_val">
                        <node_122211>node_122211_val</node_122211>
                    </node_12221>
                </g_ns:node_1222>
            </f_ns:node_122>
            <node_123>
                <node_1231 attr_1="attr_1_val">
                    <node_12311>node_12311_val</node_12311>
                </node_1231>            
            </node_123>
        </f_ns:node_12>
        <g_ns:node_13>
            <node_131>
                <g_ns:node_1311>node_1311_val</g_ns:node_1311>
                <node_1312 attr_1="attr_1_val" attr_2="attr_2_val" attr_3="attr_3_val" attr_4="attr_4_val">
                    <g_ns:node_13121/>
                </node_1312>
            </node_131>
        </g_ns:node_13>
        <node_14/>
    </node_1>
    <f_ns:node_2 attr_1="attr_1_val" attr_2="attr_2_val" attr_3="attr_3_val">
        <f_ns:node_21>node_21_val</f_ns:node_21>
    </f_ns:node_2>
</f_ns:node_0>

有一个 XSLT 代码仅用于过滤名称空间 URI:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">            
           <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
            <xsl:strip-space elements="*"/>
            <xsl:template match="*">
                <xsl:element name="{name()}" namespace="{namespace-uri()}">
                    <xsl:copy-of select="namespace::*[
                     .='http://b.com'
                     or .='http://e.com'
                     or .='http://f.com'
                     or .='http://g.com"/>
                    <xsl:copy-of select="@*"/>
                    <xsl:apply-templates/>
                </xsl:element>
            </xsl:template>
</xsl:stylesheet>

编写完整的代码非常困难,因为对 XSLT 的经验很少。
提前致谢!

您在这里有两个独立的任务:

  1. 用给定的XML;

    的元素替换命名空间used的前缀
  2. 未使用的 命名空间的声明添加到根元素。

第一个任务非常简单,因为前缀根据定义并不重要。您需要做的就是使用您想要的前缀声明命名空间,然后使用新前缀重命名相应命名空间中的元素。

如果您知道根元素的名称空间 URI,那么第二个任务可能很简单——正如您在评论中所说的那样。然后您可以将命名空间声明从样式表复制到该命名空间中的元素(并希望处理器足够聪明,只执行一次):

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:b_ns="http://b.com" 
xmlns:e_ns="http://e.com"
xmlns:f_ns="http://f.com"
xmlns:g_ns="http://g.com">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="b_ns:*">
    <xsl:element name="b_ns:{local-name()}">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

<xsl:template match="e_ns:*">
    <xsl:element name="e_ns:{local-name()}">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

<!-- this matches the root element -->
<xsl:template match="f_ns:*">
    <xsl:element name="f_ns:{local-name()}">
        <xsl:copy-of select="document('')/xsl:stylesheet/namespace::*[not(name()='xsl')]"/>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

<xsl:template match="g_ns:*">
    <xsl:element name="g_ns:{local-name()}">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

<xsl:template match="*">
    <xsl:element name="{name()}" namespace="{namespace-uri()}">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>

注:

None这个应该是必须的。如上所述,命名空间前缀没有意义。未使用的名称空间声明是多余的。显然,这个“问题”是由接收端的不符合标准的解析器引起的 - 解决这个问题会更有成效。