如何获取具有相同名称的元素并根据 XSLT 中的子节点值对它们进行排序
Posted
技术标签:
【中文标题】如何获取具有相同名称的元素并根据 XSLT 中的子节点值对它们进行排序【英文标题】:How to fetch elements with same name and order them based on a subnode value in XSLT 【发布时间】:2021-03-14 07:39:43 【问题描述】:我正在尝试转换一个输入 XML,其中所有父节点都说“x”需要被提取、排序,然后根据它们的子节点说“y”值在最终输出 XML 中重新排序。下面是我的 XML,我正在尝试对其进行修改,以便最终的 XML 将元素按升序排列,其中排序是基于 xpath notes/notesBODY/group/text
中的数值完成的,基本上是元素 <text>1. </text>
存在于所有 @987654323 @元素。但是输出 XML 并不像预期的那样,因为我似乎无法弄清楚如何在 XSLT 中准确地使用排序。任何帮助表示赞赏。
输入 XML:
<root>
<group>
<text>group1</text>
</group>
<group>
<text>group2</text>
</group>
<notes>
<notesText>notes1</notesText>
<notesBODY>
<group>
<text>2. </text>
<text>notesbody1</text>
</group>
</notesBODY>
</notes>
<notes>
<notesText>notes2</notesText>
<notesBODY>
<group>
<text>1. </text>
<text>notesbody2</text>
</group>
</notesBODY>
</notes>
<notes>
<notesText>notes3</notesText>
<notesBODY>
<group>
<text>3. </text>
<text>notesbody3</text>
</group>
</notesBODY>
</notes>
<group>
<text>group3</text>
<notes>
<notesText>notes4</notesText>
<notesBODY>
<group>
<text>4. </text>
<text>notesbody4</text>
</group>
</notesBODY>
</notes>
</group>
<group>
<text>group4</text>
</group>
<group>
<text>group5</text>
<notes>
<notesText>notes5</notesText>
<notesBODY>
<group>
<text>6. </text>
<text>notesbody5</text>
</group>
</notesBODY>
</notes>
</group>
<notes>
<notesText>notes6</notesText>
<notesBODY>
<group>
<text>5. </text>
<text>notesbody6</text>
</group>
</notesBODY>
</notes>
<group>
<text>group6</text>
</group>
<group>
<text>group7</text>
</group>
<group>
<text>group8</text>
<notes>
<notesText>notes7</notesText>
<notesBODY>
<group>
<text>8. </text>
<text>notesbody7</text>
</group>
</notesBODY>
</notes>
</group>
<notes>
<notesText>notes8</notesText>
<notesBODY>
<group>
<text>7. </text>
<text>notesbody8</text>
</group>
</notesBODY>
</notes>
<group>
<text>group9</text>
</group>
</root>
预期输出:
<root>
<group>
<text>group1</text>
</group>
<group>
<text>group2</text>
</group>
<group>
<text>group3</text>
</group>
<group>
<text>group4</text>
</group>
<group>
<text>group5</text>
</group>
<group>
<text>group6</text>
</group>
<group>
<text>group7</text>
</group>
<group>
<text>group8</text>
</group>
<group>
<text>group9</text>
</group>
<notes>
<notesText>notes2</notesText>
<notesBODY>
<group>
<text>1. </text>
<text>notesbody2</text>
</group>
</notesBODY>
</notes>
<notes>
<notesText>notes1</notesText>
<notesBODY>
<group>
<text>2. </text>
<text>notesbody1</text>
</group>
</notesBODY>
</notes>
<notes>
<notesText>notes3</notesText>
<notesBODY>
<group>
<text>3. </text>
<text>notesbody3</text>
</group>
</notesBODY>
</notes>
<notes>
<notesText>notes4</notesText>
<notesBODY>
<group>
<text>4. </text>
<text>notesbody4</text>
</group>
</notesBODY>
</notes>
<notes>
<notesText>notes6</notesText>
<notesBODY>
<group>
<text>5. </text>
<text>notesbody6</text>
</group>
</notesBODY>
</notes>
<notes>
<notesText>notes5</notesText>
<notesBODY>
<group>
<text>6. </text>
<text>notesbody5</text>
</group>
</notesBODY>
</notes>
<notes>
<notesText>notes8</notesText>
<notesBODY>
<group>
<text>7. </text>
<text>notesbody8</text>
</group>
</notesBODY>
</notes>
<notes>
<notesText>notes7</notesText>
<notesBODY>
<group>
<text>8. </text>
<text>notesbody7</text>
</group>
</notesBODY>
</notes>
</root>
XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="notes">
<xsl:apply-templates select="@*" />
<xsl:copy>
<xsl:apply-templates select="node()">
<xsl:sort select="notesBODY/group/text[position() = 0]" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
【问题讨论】:
【参考方案1】:我想你基本上想使用两个模板
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="root">
<xsl:copy>
<xsl:apply-templates select="group"/>
<xsl:apply-templates select=".//notes">
<xsl:sort select="notesBODY/group/text[1]"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="group">
<xsl:copy>
<xsl:apply-templates select="* except notes"/>
</xsl:copy>
</xsl:template>
显然你已经有了身份转换。
【讨论】:
@Martin Honnen,无论我尝试多么接近,因为我为您提供的解决方案的模拟输入 xml 可以完美地对节点进行排序。对于我的实际输入 xml,我做了一点改动,而不是 ,我使用了 ,然后“注释”被完美排序,谢谢!然而,所有其他输入 XML 标记都被删除,我的实际输入 xml 在根级别有许多其他标记。它还具有组和注释级别的属性。我原以为身份模板会处理这种情况,但看起来不是。你能推荐一下吗? @Martin Honnen,我还注意到最终输出中缺少我的实际 xml 中的“组”标签的属性,我该如何复制这些属性? 如果有group
或root
属性之一,则需要使用<xsl:copy><xsl:apply-templates select="@*"/>...</xsl:copy>
(其中...
是我在上面的代码中显示的)。我不知道为什么您认为您需要更改模板的匹配项,但又希望代码能够完成相同的工作,也许将其作为一个单独的问题提出。
@Martin Honnen,我使用了<xsl:copy-of select="@*" />
而不是<xsl:apply-templates select="@*"/>
,它决定保留属性。这也可以使用吗?对于我发现的模板匹配,使用"\"
是错误的,我使用了group
节点的父节点,它完美运行!
如果您知道只需要复制属性,那么xsl:copy-of
绝对没问题,apply-templates
在使用身份转换作为基本模板的情况下更加通用,一旦您需要更改属性,您只需添加一个模板即可。以上是关于如何获取具有相同名称的元素并根据 XSLT 中的子节点值对它们进行排序的主要内容,如果未能解决你的问题,请参考以下文章