2013-05-13 112 views
2

我正在尝试将具有相同值的兄弟姐妹紧接在一起。但是我很难仅选择IMMEDIATE兄弟姐妹。使用XPath - 如何选择/计算即时兄弟?

输入:

<ROWS> 
    <ROW> 
     <MONTH>1</MONTH> 
     <START_DATE>15/04/2013</START_DATE> 
     <RATE_AMOUNT>10</RATE_AMOUNT> 
     <DISCOUNT>-2</DISCOUNT> 
    </ROW> 
    <ROW> 
     <MONTH>2</MONTH> 
     <START_DATE>15/05/2013</START_DATE> 
     <RATE_AMOUNT>10</RATE_AMOUNT> 
     <DISCOUNT>-2</DISCOUNT> 
    </ROW> 
    <ROW> 
     <MONTH>3</MONTH> 
     <START_DATE>15/06/2013</START_DATE> 
     <RATE_AMOUNT>10</RATE_AMOUNT> 
     <DISCOUNT>-5</DISCOUNT> 
    </ROW> 
    <ROW> 
     <MONTH>4</MONTH> 
     <START_DATE>15/07/2013</START_DATE> 
     <RATE_AMOUNT>10</RATE_AMOUNT> 
     <DISCOUNT>-2</DISCOUNT> 
    </ROW> 
</ROWS> 

预期输出:

<RateList> 
    <Rate> 
     <NoOfMonths>2</NoOfMonths> 
     <StartDate>15/04/2013</StartDate> 
     <RateAmount>10</RateAmount> 
     <Discount>-2</Discount> 
    </Rate> 
    <Rate> 
     <NoOfMonths>1</NoOfMonths> 
     <StartDate>15/06/2013</StartDate> 
     <RateAmount>10</RateAmount> 
     <Discount>-5</Discount> 
    </Rate> 
    <Rate> 
     <NoOfMonths>1</NoOfMonths> 
     <StartDate>15/07/2013</StartDate> 
     <RateAmount>10</RateAmount> 
     <Discount>-2</Discount> 
    </Rate> 
</RateList> 

这是我的XSL:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:template match="/"> 
     <RateList> 
      <xsl:apply-templates/> 
     </RateList> 
    </xsl:template> 
    <xsl:template match="ROW"> 
     <xsl:variable name="noOfMonths" select=".|following-sibling::*[RATE_AMOUNT=current()/RATE_AMOUNT][DISCOUNT=current()/DISCOUNT]"/> 
     <xsl:if test="not(preceding-sibling::*[RATE_AMOUNT=current()/RATE_AMOUNT][DISCOUNT=current()/DISCOUNT])"> 
      <Rate> 
       <NoOfMonths> 
        <xsl:value-of select="count($noOfMonths)"/> 
       </NoOfMonths>  
       <StartDate> 
        <xsl:value-of select="START_DATE"/> 
       </StartDate> 
       <RateAmount> 
        <xsl:value-of select="RATE_AMOUNT"/> 
       </RateAmount> 
       <Discount> 
        <xsl:value-of select="DISCOUNT"/> 
       </Discount> 
      </Rate> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

这是我得到的输出:

<RateList> 
    <Rate> 
     <NoOfMonths>3</NoOfMonths> 
     <StartDate>15/04/2013</StartDate> 
     <RateAmount>10</RateAmount> 
     <Discount>-2</Discount> 
    </Rate> 
    <Rate> 
     <NoOfMonths>1</NoOfMonths> 
     <StartDate>15/06/2013</StartDate> 
     <RateAmount>10</RateAmount> 
     <Discount>-5</Discount> 
    </Rate> 
</RateList> 

有人可以帮忙吗?我如何选择/计数只有直接兄弟姐妹?

谢谢!

+0

你可以使用XSLT 2.0吗? – 2013-05-13 00:42:24

+0

不幸的是,没有:( – elefant 2013-05-13 00:45:11

回答

1

试试这个(有些解释在XSLT评论):

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:template match="/"> 
     <RateList> 
      <xsl:apply-templates select="*/ROW"/> 
     </RateList> 
    </xsl:template> 
    <xsl:template match="ROW"> 

     <!--Look for preceding row which has not the same data (RATE_AMOUNT and DISCOUNT) as the current. 
     And generate a id, here month concatenated with an '#'.--> 
     <xsl:variable name="notSameData" 
        select="concat(preceding-sibling::ROW 
         [not(RATE_AMOUNT=current()/RATE_AMOUNT 
         and DISCOUNT=current()/DISCOUNT)][1]/MONTH,'#')"/> 

     <!--Count following month which has same data as current 
     and also the same preceding month with not the same data as the current--> 
     <xsl:variable name="noOfMonths" 
         select="count(following-sibling::* 
          [ RATE_AMOUNT=preceding-sibling::*[1]/RATE_AMOUNT and 
           DISCOUNT = preceding-sibling::*[1]/DISCOUNT] 
          [ 
            concat(preceding-sibling::ROW 
            [not(RATE_AMOUNT=current()/RATE_AMOUNT 
            and DISCOUNT=current()/DISCOUNT)][1]/MONTH,'#') = $notSameData 
          ]) +1 "/> 

     <!--Output only for rows which don not have a not a direct (first) preceding one with same data.--> 
     <xsl:if test="not(preceding-sibling::ROW[1][RATE_AMOUNT=current()/RATE_AMOUNT][DISCOUNT=current()/DISCOUNT])"> 
       <Rate> 
       <NoOfMonths> 
        <xsl:value-of select="$noOfMonths"/> 
       </NoOfMonths> 
       <StartDate> 
        <xsl:value-of select="START_DATE"/> 
       </StartDate> 
       <RateAmount> 
        <xsl:value-of select="RATE_AMOUNT"/> 
       </RateAmount> 
       <Discount> 
        <xsl:value-of select="DISCOUNT"/> 
       </Discount> 
      </Rate> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

将产生以下输出:

<?xml version="1.0"?> 
<RateList> 
    <Rate> 
    <NoOfMonths>2</NoOfMonths> 
    <StartDate>15/04/2013</StartDate> 
    <RateAmount>10</RateAmount> 
    <Discount>-2</Discount> 
    </Rate> 
    <Rate> 
    <NoOfMonths>1</NoOfMonths> 
    <StartDate>15/06/2013</StartDate> 
    <RateAmount>10</RateAmount> 
    <Discount>-5</Discount> 
    </Rate> 
    <Rate> 
    <NoOfMonths>1</NoOfMonths> 
    <StartDate>15/07/2013</StartDate> 
    <RateAmount>10</RateAmount> 
    <Discount>-2</Discount> 
    </Rate> 
</RateList> 

评论:我没有使用xlt:key,因为我最喜欢的xlst处理器xsltproc不支持xls:key语句中的current()。

+0

谢谢!这是完美的! – elefant 2013-05-13 22:32:58

+0

很高兴我可以帮到你能标记答案是有效的吗?如果你不知道如何看待:http:///stackoverflow.com/faq#howtoask – 2013-05-14 08:14:13

-1

通过直接兄弟姐妹我了解兄弟姐妹只是在上面和下面。在这种情况下,您可以使用position()函数进行限制。我刚开始这个学我自己,但它可能是像

following-sibling::*[1] 

preceding-sibling::*[1] 
+0

这不会产生预期的输出 – 2013-05-13 09:35:59