我正在尝试将元素组拆分为包含一组唯一元素的组,同时保持拆分中的所有兄弟关系。例如,我想要以下xml:
<group>
<b074>11</b074>
<b075>03</b075>
<b076>9</b076>
<b075>04</b075>
<b076>12</b076>
</group>
<group>
<b074>11</b074>
<b075>04</b075>
<b076>4</b076>
</group>
转变为:
<group>
<b074>11</b074>
<b075>03</b075>
<b076>9</b076>
</group>
<group>
<b074>11</b074>
<b075>04</b075>
<b076>12</b076>
</group>
<group>
<b074>11</b074>
<b075>04</b075>
<b076>4</b076>
</group>
编辑:初始数据中的第一个组具有重复元素。例如,元素<b075>
出现两次。我希望第二次出现的<b075>
成为结果中的新组。这就是我所说的独特集合。
编辑#2:忘记提及当第二个<b075>
被拉入其自己的组时,其兄弟<b074>
被“复制”。这就是我保持兄弟姐妹的意思。
编辑#3 :(我道歉,我应该第一次更彻底地解释这一点)你知道<b074>
属于结果组的方式是因为它出现一次。原始组中出现一次的所有元素都由所有结果组共享。重复元素也将按顺序列出,这意味着如果元素<b075>
和<b076>
重复,它们将彼此相邻,<b075>
,然后立即<b076>
。因此,结果组的数量是这些重复元素的数量(在本例中为2)。
不幸的是,我是XSLT的新手,但我尝试应用在XSLT split a tree at a descendent node和Move separator elements upwards in xml hierarchy找到的解决方案的变体失败,因为它们似乎非常接近我想要实现的目标。< / p>
我使用1.0 - 2.0不适合我。任何帮助将不胜感激。
答案 0 :(得分:4)
如果我理解你的条件是正确的,那么转变就是你想要的:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="group">
<xsl:apply-templates select="*[1]" mode="group"/>
</xsl:template>
<xsl:template match="*" mode="group">
<xsl:param name="level" select="0"/>
<xsl:variable name="name" select="name()"/>
<xsl:variable name="needs-group" select="count( preceding-sibling::*[ name() = $name ] ) = $level"/>
<xsl:if test="$needs-group">
<group>
<xsl:apply-templates select="preceding-sibling::*[ name() != $name ]" mode="item-group">
<xsl:with-param name="level" select="$level"/>
</xsl:apply-templates>
<xsl:apply-templates select="."/>
<xsl:apply-templates select="following-sibling::*[ name() != $name ]" mode="item-group">
<xsl:with-param name="level" select="$level"/>
</xsl:apply-templates>
</group>
</xsl:if>
<xsl:apply-templates select="following-sibling::*[1]" mode="group">
<xsl:with-param name="level" select="$level + $needs-group"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*" mode="item-group">
<xsl:param name="level"/>
<xsl:variable name="name" select="name()"/>
<xsl:if test="( count( preceding-sibling::*[ name() = $name ] ) = $level ) or ( count( ../*[ name() = $name ] ) <= $level and not( following-sibling::*[ name() = $name ] ) )">
<xsl:apply-templates select="."/>
</xsl:if>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>