我不知道这是不是最好的标题,但这就是我想做的事情:
我的输入文件:
<?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
节点在输出文档中只出现一次,并且每个子节点也只出现一次,同样适用于那些chuildren的子节点,依此类推。这同样适用于pq
节点。
每个节点只应出现一次,同时保持层次结构。基本上,我需要一个文件,我可以告诉它,哪个节点是其他节点的父节点,但我只需要为每个节点提供一次这样的信息(因此实质上,每个id应该只在输出文档中出现一次)。
在输入文档中,ip
和pq
可以包含任意数量的子节点,并且它们可以位于每个node
元素中。
我尝试在按ip
分组的所有@id
元素上使用for-each-group,但我无法弄清楚如何从那里开始。我需要递归地执行此操作吗?
我会感谢您的提示和帮助!
答案 0 :(得分: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
属性标识ip
和pq
元素时,会创建您根据需要发布的输出:
<?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>