xml - 使用 XSLT 重新排列 XML 同级
问题描述
我正在使用 XSLT 将 XML 文档转换为具有更多意义的新 XML 文档。源 XML:
<root>
<A>
<country>Italy</country>
<city>Rome</city>
<score>13</score>
</A>
<A>
<country>Italy</country>
<city>Florence</city>
<score>14</score>
</A>
<A>
<country>France</country>
<city>Paris</city>
<score>20</score>
</A>
</root>
节点<country>
和都是兄弟姐妹<city>
。<score>
我的问题是:如何在 XSLT 中像这样重新排列兄弟姐妹?
<country>
<city>
<score>
</score>
</city>
</country>
我预期的 XML:
<root>
<Italy>
<Rome>
<score>13</score>
</Rome>
<Florence>
<score>14</score>
</Florence>
</Italy>
<France>
<Paris>
<score>20</score>
</Paris>
</France>
</root>
解决方案
XSLT-1.0 解决方案如下。它使用Muenchian Grouping作为一种方法来获得独特的国家价值。
编辑:
为了确保元素名称是有效的 QNames,我添加了一个translate(...)
表达式,它将相应城市名称或国家名称中的所有空格转换为下划线。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="countries" match="A" use="country" />
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="text()" />
<xsl:template match="A[generate-id(.) = generate-id(key('countries',country)[1])]">
<xsl:element name="{translate(country,' ','_')}">
<xsl:for-each select="key('countries',country)">
<xsl:element name="{translate(city,' ','_')}">
<xsl:copy-of select="score" />
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
XSLT-2.0 解决方案更简单,因为它可以使用xsl:for-each-group
:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/*">
<xsl:copy>
<xsl:for-each-group select="A" group-by="country">
<xsl:element name="{translate(current-grouping-key(),' ','_')}">
<xsl:for-each select="current-group()">
<xsl:element name="{translate(city,' ','_')}">
<xsl:copy-of select="score" />
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
两种方法的输出是相同的:
<?xml version="1.0"?>
<root>
<Italy>
<Rome>
<score>13</score>
</Rome>
<Florence>
<score>14</score>
</Florence>
</Italy>
<France>
<Paris>
<score>20</score>
</Paris>
</France>
</root>
推荐阅读
- c++ - 如何使用 std::experimental::simd?
- c++ - 您可以将整个网页嵌入到 C++ 源代码中吗?
- c++ - 如何将数组传递给函数,以便用户可以随意订购“短语”/数组
- java - 如何返回没有前 2 个字符的字符串?
- assembly - 汇编 x86 imul 误解
- swift - cgpoint 的颜色会更改所有行,并且应该只更改新行
- python - 为什么在没有 init 的情况下使用顶级目录的导入在 Python 中工作?
- python - gRPC:从装饰器或 ServiceInterceptor 将属性添加到上下文
- oracle - 事实表中的事实值或度量是什么意思?
- java - IE11 和 Safari 没有将授权标头传递给后端