Subtract in xslt 1.0 with sorting nodes

2019-09-17 14:09发布

But I have other problem with subtract value B and P for each event. Source code is for example like this:

<EVENTS>
<ROW ID="204" ID_PLACE="1" EVENT_TYPE="B" EVENT_NAME="TEST1" EVENT_ID="201">
<PRICE>
<ROW EVENT_PRICE="165,00"/>
</PRICE>
</ROW>
<ROW ID="205" ID_PLACE="1" EVENT_TYPE="P" EVENT_NAME="TEST1" EVENT_ID="201">
<PRICE>
<ROW EVENT_PRICE="125,00"/>
</PRICE>
</ROW>
<ROW ID="206" ID_PLACE="1" EVENT_TYPE="B" EVENT_NAME="TEST2" EVENT_ID="202">
<PRICE>
<ROW EVENT_PRICE="100,00"/>
</PRICE>
</ROW>
<ROW ID="207" ID_PLACE="1" EVENT_TYPE="P" EVENT_NAME="TEST2" EVENT_ID="202">
<PRICE>
<ROW EVENT_PRICE="135,00"/>
</PRICE>
</ROW>
</EVENTS>

and I have to get something like that:

<EVENT_ID>201</EVENT_ID>
<DIFF>40.00</DIFF>
<EVENT_ID>202</EVENT_ID>
<DIFF>-35.00</DIFF>

etc. In this case I now what EVENT_ID is in file, but not always it is only this two ID so I can't do this like this: for ID=201 diff is 40, for 202 diff is -35. How to write xsl transform for every ID_EVENT which is in the source code.

标签: xml xslt
3条回答
三岁会撩人
2楼-- · 2019-09-17 14:31

Another way is to use grouping:

XSLT 2.0

<xsl:for-each-group select="EVENTS/ROW" group-by="EVENT_ID">
  <xsl:variable name="B" select="current-group()[EVENT_TYPE='B']/PRICE/ROW/@EVENT_PRICE"/>
  <xsl:variable name="P" select="current-group()[EVENT_TYPE='P']/PRICE/ROW/@EVENT_PRICE"/>               
  <xsl:variable name="diff" select="translate($B, ',', '.') - translate($P, ',', '.')" />
  <EVENT_ID>
     <xsl:value-of select="current-grouping-key()" />
  </EVENT_ID>
  <DIFF>
     <xsl:value-of select="format-number($diff, '0.00')" />
  </DIFF>
</xsl:for-each-group>
查看更多
来,给爷笑一个
3楼-- · 2019-09-17 14:45

In my answer to your previous question, I remarked that there are other ways to approach the problem of matching corresponding <ROW> elements than looking for those with a common <EVENTS> parent. The situation presented in this question requires such an approach.

One might do that with keys or with XSLT 2.0 grouping, as other answers suggest. But another way would be simply to write a suitable XPath expression to select the 'P' row matching each 'B' row (or vise versa). For example,

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
  <xsl:strip-space elements="*"/>
  <xsl:decimal-format decimal-separator="." zero-digit="0" minus-sign="-" />

  <!-- transform based on 'B' rows   -->
  <xsl:template match="EVENTS/ROW[@EVENT_TYPE = 'B']">
    <xsl:variable name="event-id" select="@EVENT_ID"/>
    <!-- select the corresponding 'P' row, if any -->
    <xsl:variable name="event-p" select="../ROW[@EVENT_TYPE = 'P' and @EVENT_ID = $event-id]"/>
    <!-- supposing that there was a matching 'P' row ... -->
    <xsl:if test="$event-p">
      <!-- extract the two rows' prices here to simplify later expressions -->
      <xsl:variable name="b-price"
          select="number(translate(PRICE/ROW/@EVENT_PRICE, ',', '.'))"/>
      <xsl:variable name="p-price"
          select="number(translate($event-p/PRICE/ROW/@EVENT_PRICE, ',', '.'))"/>
      <!-- Add the wanted elements to the result tree -->
      <EVENT_ID>
        <xsl:value-of select="$event-id"/>
      </EVENT_ID>
      <DIFF>
        <!-- If you require the specific numeric format you presented, then 
             you need to ask for it -->
        <xsl:value-of select="format-number($b-price - $p-price, '0.00;-0.00')" />
      </DIFF>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>
查看更多
Ridiculous、
4楼-- · 2019-09-17 14:55

I would use a key to link the rows by their EVENT_ID:

XSLT 1.0

<xsl:stylesheet version="1.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:key name="p" match="ROW[@EVENT_TYPE='P']" use="@EVENT_ID" />

<xsl:template match="/EVENTS">
    <EVENTS>
        <xsl:for-each select="ROW[@EVENT_TYPE='B']">
            <xsl:variable name="B" select="PRICE/ROW/@EVENT_PRICE"/>
            <xsl:variable name="P" select="key('p', @EVENT_ID)/PRICE/ROW/@EVENT_PRICE"/>
            <xsl:variable name="diff" select="translate($B, ',', '.') - translate($P, ',', '.')" />
            <EVENT_ID>
                <xsl:value-of select="@EVENT_ID" />
            </EVENT_ID>
            <DIFF>
                <xsl:value-of select="format-number($diff, '0.00')" />
            </DIFF>
        </xsl:for-each>
    </EVENTS>
</xsl:template>

</xsl:stylesheet>

Demo: http://xsltransform.net/bEzjRJW

查看更多
登录 后发表回答