过滤名称空间并将其前缀替换为 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
的经验很少。
提前致谢!
您在这里有两个独立的任务:
用给定的XML;
的元素替换命名空间used的前缀
将 未使用的 命名空间的声明添加到根元素。
第一个任务非常简单,因为前缀根据定义并不重要。您需要做的就是使用您想要的前缀声明命名空间,然后使用新前缀重命名相应命名空间中的元素。
如果您知道根元素的名称空间 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这个应该是必须的。如上所述,命名空间前缀没有意义。未使用的名称空间声明是多余的。显然,这个“问题”是由接收端的不符合标准的解析器引起的 - 解决这个问题会更有成效。
我如何只保留所需的名称空间 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
的经验很少。
提前致谢!
您在这里有两个独立的任务:
用给定的XML;
的元素替换命名空间used的前缀将 未使用的 命名空间的声明添加到根元素。
第一个任务非常简单,因为前缀根据定义并不重要。您需要做的就是使用您想要的前缀声明命名空间,然后使用新前缀重命名相应命名空间中的元素。
如果您知道根元素的名称空间 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这个应该是必须的。如上所述,命名空间前缀没有意义。未使用的名称空间声明是多余的。显然,这个“问题”是由接收端的不符合标准的解析器引起的 - 解决这个问题会更有成效。