XSLT 分组和合并节点
XSLT Grouping and merging nodes
是否可以对节点进行分组并与指定键合并?我的一些 xml 文件在两个子节点中包含有关一个人的信息,我想查找节点是否与同一个人有关,然后将其合并为一个节点
输入 xml 如下所示:
<db>
<next>
<name>John</name>
<surname>Smith</surname>
<number>304888</number>
<details>
<city>Westfield</city>
<zip-code>07090</zip-code>
<address>23 Victoria Street</address>
<phone>123456789</phone>
<fax/>
</details>
</next>
<next>
<name>John</name>
<surname>Smith</surname>
<number>304888</number>
<details>
<city>Westfield</city>
<zip-code>07090</zip-code>
<address>23 Victoria Street</address>
<phone>223344123</phone>
<fax>993456789</fax>
</details>
</next>
<next>
<name>John</name>
<surname>Smith</surname>
<number>113190</number>
<details>
<city>Richmond</city>
<zip-code>3121</zip-code>
<address>18 Seasame Street</address>
<phone>123456222</phone>
<fax/>
</details>
</next>
<next>
<name>John</name>
<surname>Smith</surname>
<number>113190</number>
<details>
<city>Richmond</city>
<zip-code>3133</zip-code>
<address>23 Baker Street</address>
<phone>113344123</phone>
<fax>133456789</fax>
</details>
</next>
</db>
'number'是一个人的ID,可以有更多的人同名同姓但'number'值不同。此外,同一个人可能不止一次(具有相同的 'name'、'surename' 和 'number' 值)但具有不同的详细信息。如果 'city'、'zip-code' 和 'address' 的组合相同,但 'phone' or/and 'fax' 不同,那么我想合并它。
我希望它看起来像这样:
<db>
<next>
<name>John</name>
<surname>Smith</surname>
<number>304888</number>
<details>
<city>Westfield</city>
<zip-code>07090</zip-code>
<address>23 Victoria Street</address>
<phone>123456789</phone>
<phone>223344123</phone>
<fax>993456789</fax>
</details>
</next>
<next>
<name>John</name>
<surname>Smith</surname>
<number>113190</number>
<details>
<city>Richmond</city>
<zip-code>3121</zip-code>
<address>18 Seasame Street</address>
<phone>123456222</phone>
<fax/>
</details>
</next>
<next>
<name>John</name>
<surname>Smith</surname>
<number>113190</number>
<details>
<city>Richmond</city>
<zip-code>3133</zip-code>
<address>23 Baker Street</address>
<phone>113344123</phone>
<fax>133456789</fax>
</details>
</next>
</db>
我尝试过 muenchian 分组,但我不知道如何使用 phone 和传真节点。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:key name="index" match="next" use="number" />
<xsl:key name="details-key" match="details" use="city,'_',zip-code,'_',address" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="db">
<xsl:copy>
<xsl:for-each select="//next[generate-id() = generate-id(key('index', number)[1])]">
<xsl:element name="name">
<xsl:value-of select="name"/>
</xsl:element>
<xsl:element name="surname">
<xsl:value-of select="surname"/>
</xsl:element>
<xsl:element name="number">
<xsl:value-of select="number"/>
</xsl:element>
<next>
<xsl:for-each select="//details[generate-id() = generate-id(key('details-key', concat(city,'_',zip-code,'_',address))[1])]">
<xsl:element name="city">
<xsl:value-of select="city"/>
</xsl:element>
<xsl:element name="zip-code">
<xsl:value-of select="zip-code"/>
</xsl:element>
<xsl:element name="address">
<xsl:value-of select="address"/>
</xsl:element>
</xsl:for-each>
</next>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
首先,您的样式表会产生错误,因为您在以下中使用的表达式:
<xsl:key name="details-key" match="details" use="city,'_',zip-code,'_',address" />
不是 XPath 1.0 中的有效表达式。
如果您希望通过 city
、zip-code
和 address
的组合值对 details
元素进行分组,您应该将键定义为:
<xsl:key name="details-key" match="details" use="concat(city, '_', zip-code, '_', address)" />
现在,如果我按照您的预期输出而不是您的描述,您实际上想要为 number
和地址的每个唯一组合创建一个组。所以类似的东西:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:key name="k1" match="next" use="concat(number, '_', details/city,'_', details/zip-code,'_', details/address)" />
<xsl:template match="db">
<xsl:copy>
<xsl:for-each select="next[generate-id() = generate-id(key('k1', concat(number, '_', details/city,'_', details/zip-code,'_', details/address))[1])]">
<next>
<xsl:copy-of select="name | surname | number"/>
<details>
<xsl:copy-of select="city | zip-code | address"/>
<xsl:variable name="group-details" select="key('k1', concat(number, '_', details/city,'_', details/zip-code,'_', details/address))/details" />
<xsl:copy-of select="$group-details/phone[text()] | $group-details/fax[text()]"/>
</details>
</next>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
是否可以对节点进行分组并与指定键合并?我的一些 xml 文件在两个子节点中包含有关一个人的信息,我想查找节点是否与同一个人有关,然后将其合并为一个节点
输入 xml 如下所示:
<db>
<next>
<name>John</name>
<surname>Smith</surname>
<number>304888</number>
<details>
<city>Westfield</city>
<zip-code>07090</zip-code>
<address>23 Victoria Street</address>
<phone>123456789</phone>
<fax/>
</details>
</next>
<next>
<name>John</name>
<surname>Smith</surname>
<number>304888</number>
<details>
<city>Westfield</city>
<zip-code>07090</zip-code>
<address>23 Victoria Street</address>
<phone>223344123</phone>
<fax>993456789</fax>
</details>
</next>
<next>
<name>John</name>
<surname>Smith</surname>
<number>113190</number>
<details>
<city>Richmond</city>
<zip-code>3121</zip-code>
<address>18 Seasame Street</address>
<phone>123456222</phone>
<fax/>
</details>
</next>
<next>
<name>John</name>
<surname>Smith</surname>
<number>113190</number>
<details>
<city>Richmond</city>
<zip-code>3133</zip-code>
<address>23 Baker Street</address>
<phone>113344123</phone>
<fax>133456789</fax>
</details>
</next>
</db>
'number'是一个人的ID,可以有更多的人同名同姓但'number'值不同。此外,同一个人可能不止一次(具有相同的 'name'、'surename' 和 'number' 值)但具有不同的详细信息。如果 'city'、'zip-code' 和 'address' 的组合相同,但 'phone' or/and 'fax' 不同,那么我想合并它。 我希望它看起来像这样:
<db>
<next>
<name>John</name>
<surname>Smith</surname>
<number>304888</number>
<details>
<city>Westfield</city>
<zip-code>07090</zip-code>
<address>23 Victoria Street</address>
<phone>123456789</phone>
<phone>223344123</phone>
<fax>993456789</fax>
</details>
</next>
<next>
<name>John</name>
<surname>Smith</surname>
<number>113190</number>
<details>
<city>Richmond</city>
<zip-code>3121</zip-code>
<address>18 Seasame Street</address>
<phone>123456222</phone>
<fax/>
</details>
</next>
<next>
<name>John</name>
<surname>Smith</surname>
<number>113190</number>
<details>
<city>Richmond</city>
<zip-code>3133</zip-code>
<address>23 Baker Street</address>
<phone>113344123</phone>
<fax>133456789</fax>
</details>
</next>
</db>
我尝试过 muenchian 分组,但我不知道如何使用 phone 和传真节点。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:key name="index" match="next" use="number" />
<xsl:key name="details-key" match="details" use="city,'_',zip-code,'_',address" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="db">
<xsl:copy>
<xsl:for-each select="//next[generate-id() = generate-id(key('index', number)[1])]">
<xsl:element name="name">
<xsl:value-of select="name"/>
</xsl:element>
<xsl:element name="surname">
<xsl:value-of select="surname"/>
</xsl:element>
<xsl:element name="number">
<xsl:value-of select="number"/>
</xsl:element>
<next>
<xsl:for-each select="//details[generate-id() = generate-id(key('details-key', concat(city,'_',zip-code,'_',address))[1])]">
<xsl:element name="city">
<xsl:value-of select="city"/>
</xsl:element>
<xsl:element name="zip-code">
<xsl:value-of select="zip-code"/>
</xsl:element>
<xsl:element name="address">
<xsl:value-of select="address"/>
</xsl:element>
</xsl:for-each>
</next>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
首先,您的样式表会产生错误,因为您在以下中使用的表达式:
<xsl:key name="details-key" match="details" use="city,'_',zip-code,'_',address" />
不是 XPath 1.0 中的有效表达式。
如果您希望通过 city
、zip-code
和 address
的组合值对 details
元素进行分组,您应该将键定义为:
<xsl:key name="details-key" match="details" use="concat(city, '_', zip-code, '_', address)" />
现在,如果我按照您的预期输出而不是您的描述,您实际上想要为 number
和地址的每个唯一组合创建一个组。所以类似的东西:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:key name="k1" match="next" use="concat(number, '_', details/city,'_', details/zip-code,'_', details/address)" />
<xsl:template match="db">
<xsl:copy>
<xsl:for-each select="next[generate-id() = generate-id(key('k1', concat(number, '_', details/city,'_', details/zip-code,'_', details/address))[1])]">
<next>
<xsl:copy-of select="name | surname | number"/>
<details>
<xsl:copy-of select="city | zip-code | address"/>
<xsl:variable name="group-details" select="key('k1', concat(number, '_', details/city,'_', details/zip-code,'_', details/address))/details" />
<xsl:copy-of select="$group-details/phone[text()] | $group-details/fax[text()]"/>
</details>
</next>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>