使用 XSL 删除命名空间并提取 XML 文件的子集

发布于 2024-11-18 16:35:46 字数 1057 浏览 2 评论 0原文

当我的输入 Xml 为:

 <country>
       <state>
           <city>
               <name>DELHI</name>            
           </city>
      </state>
    </country>

对于如下所需的输出:

<city>
  <name>DELHI</name>            
</city

以下 xsl 工作正常:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" omit-xml-declaration="yes" />
    <xsl:template match="/">
        <xsl:copy-of select="//city">
        </xsl:copy-of>
    </xsl:template>
</xsl:stylesheet>

但相同的 XSL 不适用于上述输入 XML,如果添加了名称空间: 如下所示:

<country xmlns="http://india.com/states" version="1.0">
   <state>
       <city>
           <name>DELHI</name>            
       </city>
  </state>
</country>

我希望名称空间与要复制的城市元素一起被删除。

任何帮助将不胜感激。 谢谢

When my Input Xml as :

 <country>
       <state>
           <city>
               <name>DELHI</name>            
           </city>
      </state>
    </country>

For required output as below:

<city>
  <name>DELHI</name>            
</city

The following xsl is working fine :

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" omit-xml-declaration="yes" />
    <xsl:template match="/">
        <xsl:copy-of select="//city">
        </xsl:copy-of>
    </xsl:template>
</xsl:stylesheet>

BUT THE SAME XSL IS NOT WORKING FOR THE ABOVE INPUT XML , IF NAME SPACE IS ADDED :
Like Below :

<country xmlns="http://india.com/states" version="1.0">
   <state>
       <city>
           <name>DELHI</name>            
       </city>
  </state>
</country>

I want the name space to be removed along with the city element to be copied .

Any help would be appreciated .
Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

墨洒年华 2024-11-25 16:35:46

这是有关 XPath、XML 和 XSLT 的最多常见问题解答。搜索“默认命名空间和 XPath 表达式”。

解决方案

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

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


 <xsl:template match="*[not(ancestor-or-self::x:city)]">
  <xsl:apply-templates/>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时

<country xmlns="http://india.com/states" version="1.0">
    <state>
        <city>
            <name>DELHI</name>
        </city>
    </state>
</country>

想要的结果生成

<city>
   <name>DELHI</name>
</city>

解释

  1. 在 XPath 中,无前缀的元素名称始终被认为位于“无命名空间”中。但是,所提供的 XML 文档中的每个元素名称都位于非空命名空间中(默认命名空间 "http://india.com/states")。因此,//city 不选择任何节点(因为 XML 文档中没有任何元素不是命名空间),而 //x:city 其中 x: 绑定到命名空间 "http://india.com/states" 选择所有城市元素(位于命名空间"http://india.com/states ").

  2. 在此转换中有两个模板。第一个模板匹配任何元素并重新创建它,但在无命名空间中。它还复制所有属性,然后将模板应用于该元素的子节点。

  3. 对于不是 city 元素的祖先或本身不是 city 元素的所有元素,第二个模板会覆盖第一个模板。这里的操作是在所有子节点上应用模板。

更新:OP修改了询问为什么在处理新的、修改的XML文档的结果中存在不需要的文本的问题:

<country xmlns="http://india.com/states" version="1.0">
        <state>
            <city>
                <name>DELHI</name>
            </city>
        </state>
        <state2>
            <city2>
                <name2>MUMBAI</name2>
            </city2>
        </state2>
</country>

为了生成文本“ MUMBAI”,上面的转换需要稍微修改一下——忽略(而不是复制)任何没有 x:city 祖先的文本节点。为此,我们添加以下一行空模板:

 <xsl:template match="text()[not(ancestor::x:city)]"/>

整个转换现在变为

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

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

     <xsl:template match="*[not(ancestor-or-self::x:city)]">
      <xsl:apply-templates/>
     </xsl:template>

     <xsl:template match="text()[not(ancestor::x:city)]"/>
</xsl:stylesheet>

结果仍然是想要的正确结果

<city>
   <name>DELHI</name>
</city>

This is the most FAQ on XPath, XML and XSLT. Search for "default namespace and XPath expressions".

As for a solution:

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

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


 <xsl:template match="*[not(ancestor-or-self::x:city)]">
  <xsl:apply-templates/>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the provided XML document:

<country xmlns="http://india.com/states" version="1.0">
    <state>
        <city>
            <name>DELHI</name>
        </city>
    </state>
</country>

the wanted result is produced:

<city>
   <name>DELHI</name>
</city>

Explanation:

  1. In XPath an unprefixed element-name is always considerd to be in "no namespace". However, every element name in the provided XML document is in a non-empty namespace (the default namespace "http://india.com/states"). Therefore, //city selects no node (as there is no element in the XML document that is no namespace), while //x:city where x: is bound to the namespace "http://india.com/states" selects all city elements (that are in the namespace"http://india.com/states").

  2. In this transformation there are two templates. The first template matches any element and re-creates it, but in no-namespace. It also copies all atributes and then applies templates to the children-nodes of this element.

  3. The second template overrides the first for all elements that are not ancestors of a city element or not themselves a city element. The action here is to apply templates on all children nodes.

UPDATE: The OP has modified the question asking why there is non-wanted text in the result of processing a new, modified XML document:

<country xmlns="http://india.com/states" version="1.0">
        <state>
            <city>
                <name>DELHI</name>
            </city>
        </state>
        <state2>
            <city2>
                <name2>MUMBAI</name2>
            </city2>
        </state2>
</country>

In order not to produce the text "MUMBAI", the transformation above needs to be slightly modified -- to ignore (not copy) any text node that hasn't an x:city ancestor. For this purpose, we add the following one-line, empty template:

 <xsl:template match="text()[not(ancestor::x:city)]"/>

The whole transformation now becomes:

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

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

     <xsl:template match="*[not(ancestor-or-self::x:city)]">
      <xsl:apply-templates/>
     </xsl:template>

     <xsl:template match="text()[not(ancestor::x:city)]"/>
</xsl:stylesheet>

and the result is still the wanted, correct one:

<city>
   <name>DELHI</name>
</city>
策马西风 2024-11-25 16:35:46

您可以使用以下模板获得所需的输出:

 <xsl:template match="*[not(ancestor-or-self::x:*[starts-with(name(),'city')])]">
  <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="/">
     <xsl:apply-templates select="//x:*[starts-with(name(),'city')]"/>
 </xsl:template>

在它提供的新输入上使用 Microsoft (R) XSLT Processor Version 4.0 进行测试:

<city>
   <name>DELHI</name>
</city>
<city2>
   <name2>MUMBAI</name2>
</city2>

You can get the wanted output by using a template like:

 <xsl:template match="*[not(ancestor-or-self::x:*[starts-with(name(),'city')])]">
  <xsl:apply-templates/>
 </xsl:template>

or

 <xsl:template match="/">
     <xsl:apply-templates select="//x:*[starts-with(name(),'city')]"/>
 </xsl:template>

Tested with Microsoft (R) XSLT Processor Version 4.0 on your new input it gives:

<city>
   <name>DELHI</name>
</city>
<city2>
   <name2>MUMBAI</name2>
</city2>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文