我想根据它们在列表中的位置将新元素内的两个元素重新组合,删除这些对的重复项,按字母顺序对它们进行排序,并为每个组赋予数字ID(使用XSLT 2.0或1.0)。我是XSLT的新手,目前对解决问题的方法一无所知。
在平坦的地标XML列表(来自数据库)中,有地标名称列表和坐标列表。需要重新排列它们,以便每个名称和坐标在新的地标元素内正确分组在一起。位置1的名称需要与第一个coord元素配对,依此类推。
在过去三天中,我在stackoverflow中查找了有关重新分组,重复删除,muenchian分组的主题,并尝试了已发布的示例,但无法将其应用于我的案例。
简化的输入文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<landmarklist>
<citylist id="1">
<landmark type="city">
<name>London</name>
</landmark>
<landmark>
<name>Tower Bridge</name>
<name>Big Ben</name>
<name>St Paul's Cathedral</name>
<name>Big Ben</name>
<coord>51°30′20″N 0°04′31″W</coord>
<coord>51° 30′ 3″ N, 0° 7′ 28″ W</coord>
<coord>51° 30′ 49″ N, 0° 5′ 53″ W</coord>
<coord>51° 30′ 3″ N, 0° 7′ 28″ W</coord>
</landmark>
</citylist>
<citylist id="2">
<landmark type="city">
<name>Paris</name>
</landmark>
<landmark>
<name>Eiffel Tower</name>
<name>Arc de Triomphe</name>
<name>Louvre</name>
<coord>48° 51′ 29.6″ N, 2° 17′ 40.2″ E</coord>
<coord>48° 52′ 25.68″ N, 2° 17′ 42″ E</coord>
<coord>48° 51′ 40″ N, 2° 20′ 11″ E</coord>
</landmark>
</citylist>
<citylist id="3">
<landmark type="city">
<name>Madrid</name>
</landmark>
<landmark>
<name>Plaza Mayor</name>
<name>Almudena Cathedral</name>
<coord>40° 24′ 55.31″ N, 3° 42′ 26.63″ W</coord>
<coord>40° 24′ 56.11″ N, 3° 42′ 52.41″ W</coord>
</landmark>
</citylist>
</landmarklist>
生成的输出文件应如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<landmarklist>
<citylist id="1">
<landmark type="city">
<name>London</name>
</landmark>
<landmark id="1">
<name>Big Ben</name>
<coord>51° 30′ 3″ N, 0° 7′ 28″ W</coord>
</landmark>
<landmark id="2">
<name>St Paul's Cathedral</name>
<coord>51° 30′ 49″ N, 0° 5′ 53″ W</coord>
</landmark>
<landmark id="3">
<name>Tower Bridge</name>
<coord>51°30′20″N 0°04′31″W</coord>
</landmark>
</citylist>
<citylist id="2">
<landmark type="city">
<name>Paris</name>
</landmark>
<landmark>
<name id="4">Arc de Triomphe</name>
<coord>48° 52′ 25.68″ N, 2° 17′ 42″ E</coord>
</landmark>
<landmark>
<name id="5">Eiffel Tower</name>
<coord>48° 51′ 29.6″ N, 2° 17′ 40.2″ E</coord>
</landmark>
<landmark id="6">
<name>Louvre</name>
<coord>48° 51′ 40″ N, 2° 20′ 11″ E</coord>
</landmark>
</citylist>
<citylist id="3">
<landmark type="city">
<name>Madrid</name>
</landmark>
<landmark id="7">
<name>Plaza Mayor</name>
<coord>40° 24′ 55.31″ N, 3° 42′ 26.63″ W</coord>
</landmark>
<landmark id="8">
<name>Almudena Cathedral</name>
<coord>40° 24′ 56.11″ N, 3° 42′ 52.41″ W</coord>
</landmark>
</citylist>
</landmarklist>
为了使用键来对名称和coord元素进行分组,我使用了一个单独的转换来添加ID(并且我临时重命名了城市名称,以便不计入ID)。还是可以在自己的转换方案中管理一切?
<landmark>
<name id="1">Tower Bridge</name>
<name id="2">Big Ben</name>
<name id="3">St Paul's Cathedral</name>
<name id="4">Big Ben</name>
<coord id="1">51°30′20″N 0°04′31″W</coord>
<coord id="2">51° 30′ 3″ N, 0° 7′ 28″ W</coord>
<coord id="3">51° 30′ 49″ N, 0° 5′ 53″ W</coord>
<coord id="4">51° 30′ 3″ N, 0° 7′ 28″ W</coord>
</landmark>
但是我现在如何使用两个不同元素的ID重新组合?据我了解,我发现的示例始终使用一个示例?我对自己的工作原理缺乏了解,感到非常抱歉。
任何帮助将不胜感激。非常感谢。
答案 0 :(得分:0)
您可以在一次通过中进行分组和排序,第二次使用xsl:number
作为id
属性,以下是XSLT 3(与Saxon 9.8或更高版本或Altova 2017或更高版本兼容):< / p>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:mode name="group" on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="first-pass">
<xsl:apply-templates mode="group"/>
</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates select="$first-pass/node()"/>
</xsl:template>
<xsl:template match="citylist/landmark[not(@type)]" mode="group">
<xsl:variable name="coords" select="coord"/>
<xsl:for-each-group select="name" composite="yes" group-by="., let $p := position() return $coords[$p]">
<xsl:sort select="current-grouping-key()[1]"/>
<landmark>
<xsl:copy-of select="."/>
<coord>{current-grouping-key()[2]}</coord>
</landmark>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="citylist/landmark[not(@type)]">
<xsl:copy>
<xsl:attribute name="id">
<xsl:number level="any" count="landmark[not(@type)]"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/pPzifp8/1
如果需要,当然可以适应XSLT 2:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="2.0">
<xsl:template match="@* | node()" mode="#all">
<xsl:copy>
<xsl:apply-templates select="@*, node()" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="first-pass">
<xsl:apply-templates mode="group"/>
</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates select="$first-pass/node()"/>
</xsl:template>
<xsl:template match="citylist/landmark[not(@type)]" mode="group">
<xsl:variable name="coords" select="coord"/>
<xsl:for-each-group select="name" group-by="concat(., '|', for $p in position() return $coords[$p])">
<xsl:sort select="."/>
<landmark>
<xsl:variable name="p" select="position()"/>
<xsl:copy-of select="., $coords[$p]"/>
</landmark>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="citylist/landmark[not(@type)]">
<xsl:copy>
<xsl:attribute name="id">
<xsl:number level="any" count="landmark[not(@type)]"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>