【问题标题】:XSLT 2.0 : picking up XML node by matching one child node and comparing otherXSLT 2.0:通过匹配一个子节点并比较其他子节点来获取 XML 节点
【发布时间】:2021-03-21 17:07:51
【问题描述】:

我输入了如下的 XML:

<parent>
    <payment>
        <id>123456</id>
        <type>CANCELLED</type>
        <date>2020-12-03</date>
        <amount>100</amount>
    </payment>
    <payment>
        <id>234567</id>
        <type>FORCE</type>
        <date>2020-12-01</date>
        <amount>200</amount>
    </payment>
    <payment>
        <id>345678</id>
        <type>CANCELLED</type>
        <date>2020-12-01</date>
        <amount>300</amount>
    </payment>
    <payment>
        <id>456789</id>
        <type>FORCE</type>
        <date>2020-12-01</date>
        <amount>400</amount>
    </payment>
    <payment>
        <id>456788</id>
        <type>CANCELLED</type>
        <date>2020-12-01</date>
        <amount>500</amount>
    </payment>
</parent>

现在,我们需要 type = 'CANCELLED' 且棘手条件在这些已取消付款中的节点,如果日期相等,则我们需要选择具有最高 id 的节点。所以,在上面的示例输入中,应该只选择第 1 个和第 5 个节点。第一个节点的日期与任何其他节点都不匹配,因此被选中。虽然第 5 个节点的日期与第 3 个节点匹配,但选择第 5 个节点,因为它具有更高的 id。

为此,我尝试在XSLT下面写,

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:variable name="input" select="parent"/>
    <xsl:template match="/">
        <xsl:for-each select="parent/payment[type='CANCELLED']">
            <xsl:choose>
                <xsl:when test="date = $input/payment[type='CANCELLED']/date">
                    <xsl:message>
                        <xsl:value-of select="amount"/>
                    </xsl:message>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="amount"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

for-each 是必需的,因为在实际示例中我们正在提取一些值,因此我们需要调整 for-each 循环条件或在其中写入 if 条件。我尝试使用整个输入 xml 声明变量输入,并比较在 for-each 迭代中选择的节点与输入节点,但随后它也与 self 匹配。我是否朝着正确的方向前进?请指导。

提前致谢。

【问题讨论】:

    标签: if-statement xslt foreach xslt-2.0


    【解决方案1】:

    要识别具有相同 datepayments,请使用分组,然后在每个组中选择具有最高/最大 id 的项目:

    <xsl:for-each-group select="//payment[type = 'CANCELLED']" group-by="date">
      <xsl:copy-of select="current-group()[id = max(current-group()/id)]"/>
    </xsl:for-each-group>
    

    【讨论】:

    • 谢谢@MartinHonnen。完美!
    • 一个后续查询:当我执行 max(current-group()/id) 时,我丢失了前导零。例如,如果付款 id 为 000004984,则变为 4984。有没有办法保留前导零并同时具有最大值?
    • @SwapnilPrabhavalkar,考虑问一个新的细节问题,输入中的所有ids 是否具有相同的位数,您可以接受去除前导零的数字比较,但是将允许您稍后使用,例如`format-integer(max(current-group()/id), '0000000000') 将最大值格式化为所需的位数?
    • 感谢@MartinHonnen。我已经使用格式号解决了这个问题,因为位数是固定的(10)。
    猜你喜欢
    • 2017-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多