比较当前节点与先前的兄弟姐妹和修改兄弟姐妹

时间:2014-03-19 13:37:35

标签: xml xslt xslt-2.0 siblings

输入xml按每个元素的id排序,我正在检查当前节点是否具有与前一个兄弟相同的id。如果它们是相同的,那么我想从xml中删除(不显示)当前节点并将其一些值添加到该兄弟节点。如果id匹配,检查当前节点与任何先前节点并执行相同的逻辑将非常有用。

这是输入xml:

<?xml version="1.0"?>
<transactions>
    <transaction>
        <name>Test Entry</name>
        <id>123</id>
        <line_memo>memo1</line_memo>
        <amount>5</amount>
    </transaction>
    <transaction>
        <name>Test 1</name>
        <id>123</id>
        <line_memo>memo2</line_memo>
        <amount>10</amount>
    </transaction>
    <transaction>
        <name>Test 2</name>
        <id>123</id>
        <line_memo>memo3</line_memo>
        <amount>15</amount>
    </transaction>
    <transaction>
        <name>Test 3</name>
        <id>1235</id>
        <line_memo>0123456789</line_memo>
        <amount>30</amount>
    </transaction>
</transactions>

我的XSLT - 我一直在尝试应用模板和参数。:

    <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="transactions">
        <transactions>
        <xsl:for-each select="transaction">
            <xsl:variable name="name" select="adjustment_flag"/>
            <xsl:variable name="id" select="id"/>
            <xsl:variable name="amount" select="amount"/>
            <xsl:variable name="line_memo" select="control_amount"/>
            <xsl:variable name="invoice_date" select="invoice_number"/>

            <xsl:choose>
                <xsl:when test="(position() > 1)">
                    <xsl:choose>
                        <xsl:when test="preceding-sibling::transaction[id = $id]">
                          <transaction>
                            <xsl:apply-templates select="preceding-sibling::transaction/line_memo">
                <xsl:with-param name="newMemo" select="line_memo"/>
            </xsl:apply-templates>
                            <xsl:apply-templates select="preceding-sibling::transaction/amount">
                              <xsl:with-param name="newAmount" select="amount"/>
            </xsl:apply-templates>
                          <name><xsl:value-of select="name"/></name>
                          <id><xsl:value-of select="id"/></id>
                          <!--<line_memo><xsl:value-of select="line_memo"/></line_memo>
                          <amount><xsl:value-of select="amount"/></amount>-->
                          </transaction>
                        </xsl:when>
                        <xsl:otherwise>
                          <transaction>
                          <name><xsl:value-of select="name"/></name>
                          <id><xsl:value-of select="id"/></id>
                          <line_memo><xsl:value-of select="line_memo"/></line_memo>
                          <amount><xsl:value-of select="amount"/></amount>
                          </transaction>
                        </xsl:otherwise>
                    </xsl:choose>       
                </xsl:when>         

                <xsl:otherwise>
                  <transaction>
                  <name><xsl:value-of select="name"/></name>
                  <id><xsl:value-of select="id"/></id>
                  <line_memo><xsl:value-of select="line_memo"/></line_memo>
                  <amount><xsl:value-of select="amount"/></amount>
                  </transaction>
                </xsl:otherwise>
            </xsl:choose>               

        </xsl:for-each>
    </transactions>
    </xsl:template> 

      <xsl:template match="line_memo">
        <xsl:param name="newMemo"/>
            <new_memo><xsl:value-of select="concat(line_memo, '|', $newMemo)"/></new_memo>
    </xsl:template>
        <xsl:template match="amount">
        <xsl:param name="newAmount"/>
            <new_amount><xsl:value-of select="amount + $newAmount"/></new_amount>
    </xsl:template>
</xsl:stylesheet>

期望的输出:

<?xml version="1.0"?>
<transactions>
    <transaction>
        <name>Test Entry</name>
        <id>123</id>
        <line_memo>memo1|memo2|memo3</line_memo>
        <amount>30</amount>
    </transaction>
    <transaction>
        <name>Test 3</name>
        <id>1235</id>
        <line_memo>0123456789</line_memo>
        <amount>30</amount>
    </transaction>
</transactions>

我的输出使用上面的样式表:

    <?xml version="1.0" encoding="utf-16"?>
<transactions>
    <transaction>
        <name>Test Entry</name>
        <id>123</id>
        <line_memo>memo1</line_memo>
        <amount>5</amount>
    </transaction>
    <transaction>
        <new_memo>|memo2</new_memo>
        <new_amount>NaN</new_amount>
        <name>Test 1</name>
        <id>123</id>
    </transaction>
    <transaction>
        <new_memo>|memo3</new_memo>
        <new_memo>|memo3</new_memo>
        <new_amount>NaN</new_amount>
        <new_amount>NaN</new_amount>
        <name>Test 2</name>
        <id>123</id>
    </transaction>
    <transaction>
        <name>Test 3</name>
        <id>1235</id>
        <line_memo>0123456789</line_memo>
        <amount>30</amount>
    </transaction>
</transactions>

最终输出包含一个带有123 id的元素,并将金额相加并将备注字段与|分隔符连接起来。

在我的样式表中,我添加了apply-templates但是我收到了一个错误,它说 Required item type of @select attribute of xsl:apply-templates is node(); supplied value has item type xs:string

如何修改前面的兄弟元素并省略当前节点?

1 个答案:

答案 0 :(得分:2)

不要在“修改”已经输出的任何内容方面考虑它。您要在此处执行的操作是为共享相同ID的输入transaction元素的每个创建一个输出transaction元素。由于您使用的是XSLT 2.0,因此for-each-groupseparator上的value-of属性很容易实现:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output indent="yes" />

  <xsl:template match="/*">
    <xsl:copy>
      <!-- process all input transactions with the same id as a group -->
      <xsl:for-each-group select="transaction" group-by="id">
        <transaction>
          <!-- copy name and id from the first instance -->
          <xsl:sequence select="name, id" />
          <!-- join all the memos in the group with | - if there's only one
               then there will be no separator -->
          <line_memo>
            <xsl:value-of select="current-group()/line_memo" separator="|" />
          </line_memo>
          <!-- sum the amounts -->
          <amount>
            <xsl:value-of select="sum(current-group()/amount)" />
          </amount>
        </transaction>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

使用Saxon 9 HE对样本输入运行时,会生成所需的输出:

<?xml version="1.0" encoding="UTF-8"?>
<transactions>
   <transaction>
      <name>Test Entry</name>
      <id>123</id>
      <line_memo>memo1|memo2|memo3</line_memo>
      <amount>30</amount>
   </transaction>
   <transaction>
      <name>Test 3</name>
      <id>1235</id>
      <line_memo>0123456789</line_memo>
      <amount>30</amount>
   </transaction>
</transactions>