【问题标题】:xslt 2.0: create hierarchy that contains each node only oncexslt 2.0:创建只包含每个节点一次的层次结构
【发布时间】:2016-01-08 11:01:06
【问题描述】:

我不知道这是否是最好的标题,但这是我想做的:

我的输入文件:

 <?xml version="1.0" encoding="UTF-8"?>
    <out>
    <cat id="d1e3">
        <ip level="1" id="d1e3a1814" content="ABC">
            <ip level="2" id="d1e3a1815" content="DEF"/>
        </ip>
        <pq level="1" id="d1e3a1911" content="XPQ"/>
    </cat>
    <cat id="d1e8">
        <ip level="1" id="d1e8a1814" content="ABC">
            <ip level="2" id="d1e8a1815" content="TXTXT"/>
        </ip>
        <pq level="1" id="d1e8a1911" content="XPQ"/>
    </cat>
    <cat id="d1e13">
        <ip level="1" id="d1e13a1814" content="ABC">
            <ip level="2" id="d1e13a1815" content="TXTXT"/>
        </ip>
        <pq level="1" id="d1e13a1911" content="XPQ">
            <pq level="2" id="d1e13a1912" content="1234"/>
        </pq>
    </cat>
    <cat id="d1e569">
        <ip level="1" id="d1e569a1814" content="ABC">
            <ip level="2" id="d1e569a1815" content="TXTXT"/>
        </ip>
        <pq level="1" id="d1e569a1911" content="XPQ">
            <pq level="2" id="d1e569a1912" content="1234">
                <pq level="3" id="d1e569a1913" content="345">
                    <pq level="4" id="d1e569a1914" content="456">
                        <pq level="5" id="d1e569a1915" content="567"/>
                    </pq>
                </pq>
            </pq>
        </pq>
    </cat>
    <cat id="d1e666">
        <ip level="1" id="d1e666a1814" content="ABC">
            <ip level="2" id="d1e666a1815" content="TXTXT"/>
        </ip>
        <pq level="1" id="d1e666a1911" content="XPQ">
            <pq level="2" id="d1e666a1912" content="1234">
                <pq level="3" id="d1e666a1913" content="8787"/>
            </pq>
        </pq>
    </cat>
    </out>

我想要的输出:

 <?xml version="1.0" encoding="UTF-8"?>
    <out>
        <new level="1" id="d1e3a1814" content="ABC">
            <new level="2" id="d1e3a1815" content="DEF"/>
            <new level="2" id="d1e8a1815" content="TXTXT"/>
        </new>
         <new level="1" id="d1e13a1911" content="XPQ">
            <new level="2" id="d1e569a1912" content="1234">
                <new level="3" id="d1e569a1913" content="345">
                    <new level="4" id="d1e569a1914" content="456">
                        <new level="5" id="d1e569a1915" content="567"/>
                    </new>
                </new>
            </new>
            <new level="3" id="d1e666a1913" content="8787"/>
        </new>
    </out>

使用 xslt 2.0 和 saxon9he。

所以这里发生的事情是每个ip 节点在输出文档中只出现一次,并且它的每个子节点也只出现一次,同样适用于这些孩子的孩子等等。 pq 节点也是如此。

每个节点应该只出现一次,同时保持层次结构。基本上,我需要一个文档,我可以从中分辨出哪个节点是哪个其他节点的父节点,但是每个节点我只需要一次此信息(因此本质上,每个 id 应该只在输出文档中出现一次)。

在输入文档中,ippq 可以有任意数量的子节点,并且在每个node 元素中都可以。

我已经尝试在所有 ip 元素上使用 for-each-group 按 @id 分组,但我不知道如何从那里开始。我需要递归执行此操作吗?

非常感谢您的提示和帮助!

【问题讨论】:

  • 这已经是一个很好的问题了,但是您能否也包括您当前的 XSLT 样式表?
  • @user3629892,发布的答案有帮助吗?

标签: xml xslt xslt-2.0 saxon


【解决方案1】:

运行时

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="ip-id" match="ip" use="@id"/>
    <xsl:key name="pq-id" match="pq" use="@id"/>

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

    <xsl:template match="cat">
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="ip[. is key('ip-id', @id)[1]]">
        <new-ip>
            <xsl:apply-templates select="@* , key('ip-id', @id)/ip"/>
        </new-ip>
    </xsl:template>

    <xsl:template match="ip[not(. is key('ip-id', @id)[1])]"/>

    <xsl:template match="pq[. is key('pq-id', @id)[1]]">
        <new-pq>
            <xsl:apply-templates select="@* , key('pq-id', @id)/pq"/>
        </new-pq>
    </xsl:template>

    <xsl:template match="pq[not(. is key('pq-id', @id)[1])]"/>

</xsl:transform>

反对你的意见,我得到了结果

<out>
   <new-ip level="1" id="d1e3a1814" content="ABC">
      <new-ip level="2" id="d1e3a1815" content="DEF"/>
   </new-ip>
   <new-pq level="1" id="d1e3a1911" content="XPQ"/>
   <new-ip level="1" id="d1e8a1814" content="ABC">
      <new-ip level="2" id="d1e8a1815" content="TXTXT"/>
   </new-ip>
   <new-pq level="1" id="d1e8a1911" content="XPQ"/>
   <new-ip level="1" id="d1e13a1814" content="ABC">
      <new-ip level="2" id="d1e13a1815" content="TXTXT"/>
   </new-ip>
   <new-pq level="1" id="d1e13a1911" content="XPQ">
      <new-pq level="2" id="d1e13a1912" content="1234"/>
   </new-pq>
   <new-ip level="1" id="d1e569a1814" content="ABC">
      <new-ip level="2" id="d1e569a1815" content="TXTXT"/>
   </new-ip>
   <new-pq level="1" id="d1e569a1911" content="XPQ">
      <new-pq level="2" id="d1e569a1912" content="1234">
         <new-pq level="3" id="d1e569a1913" content="345">
            <new-pq level="4" id="d1e569a1914" content="456">
               <new-pq level="5" id="d1e569a1915" content="567"/>
            </new-pq>
         </new-pq>
      </new-pq>
   </new-pq>
   <new-ip level="1" id="d1e666a1814" content="ABC">
      <new-ip level="2" id="d1e666a1815" content="TXTXT"/>
   </new-ip>
   <new-pq level="1" id="d1e666a1911" content="XPQ">
      <new-pq level="2" id="d1e666a1912" content="1234">
         <new-pq level="3" id="d1e666a1913" content="8787"/>
      </new-pq>
   </new-pq>
</out>

我意识到你想要的结果中的节点要多得多,但我认为它们的 id 属性是独一无二的。

当使用content 属性而不是id 属性来识别ippq 元素时,会创建您想要发布的输出:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="content" match="ip | pq" use="@content"/>

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

    <xsl:template match="cat">
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="ip[. is key('content', @content)[1]] | pq[. is key('content', @content)[1]]">
        <new>
            <xsl:apply-templates select="@* , key('content', @content)/*"/>
        </new>
    </xsl:template>

    <xsl:template match="ip[not(. is key('content', @content)[1])] | pq[not(. is key('content', @content)[1])]"/>

</xsl:transform>

【讨论】:

    猜你喜欢
    • 2019-11-19
    • 2015-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-20
    相关资源
    最近更新 更多