2014-09-15 1 views
0

아래 XML 및 XSLT 버전을 제거했습니다.xml 노드가 특정 순서로되어 있지 않으면 XSL 변환이 작동하지 않습니다.

나는 거의 내가 필요로하는 것을 얻었지만, xml이 아래와 같이 주문되면 나는 'Class 2'를위한 총 행을 얻는 것처럼 보이지 않는다.

첫 번째 두 orderline 요소는 모두 'No Class'클래스 특성을 갖습니다. 이러한 요소를 마지막에 넣으면 변형이 작동합니다. 그러나 xml은 아래 순서대로 수신되므로 이와 같이 작동해야합니다.

xml의 순서가 문제가되는 것 같아서 xml을 정렬하고 변수에 넣으면 변수의 내용을 변환 할 수 있다고 생각했습니다. xslt에서 그런 식으로 할 수 있습니까

아무도 도와 줄 수 있습니까?

는 XML :

<?xml version="1.0" encoding="utf-8" standalone="no"?> 
<!DOCTYPE EmailOrder 
    SYSTEM "http://orders.bbb.co.uk/xml/Xorder.DTD"> 
<?xml-stylesheet type='text/xsl' href='BBSORG6.XSL'?> 
<EmailOrders> 
    <Order Key="COLGRE1-20140914-2345"> 
    <Customer_Msg>Class sort</Customer_Msg> 
    <OrderLine> 
     <OrderKey>COLGRE1-20140914-2345</OrderKey> 
     <ProductKey>1001</ProductKey> 
     <Qty>1</Qty> 
     <Free>0</Free> 
     <Cost>12.99</Cost> 
     <VAT_rate>0</VAT_rate> 
     <Details>Friends Character Encyclopedia </Details> 
     <Class>No Class</Class> 
     <Bags>0</Bags> 
     <Section>Funfare</Section> 
    </OrderLine> 
    <OrderLine> 
     <OrderKey>COLGRE1-20140914-2345</OrderKey> 
     <ProductKey>1002</ProductKey> 
     <Qty>2</Qty> 
     <Free>0</Free> 
     <Cost>19.98</Cost> 
     <VAT_rate>0</VAT_rate> 
     <Details>Winnie’s Big Bad Robot</Details> 
     <Class>No Class</Class> 
     <Bags>0</Bags> 
     <Section>Funfare</Section> 
    </OrderLine> 
    <OrderLine> 
     <OrderKey>COLGRE1-20140914-2345</OrderKey> 
     <ProductKey>1012</ProductKey> 
     <Qty>1</Qty> 
     <Free>0</Free> 
     <Cost>6.50</Cost> 
     <VAT_rate>0</VAT_rate> 
     <Details>Snow</Details> 
     <Class>Class 1</Class> 
     <Bags>5</Bags> 
     <Section>Funfare</Section> 
    </OrderLine> 
    <OrderLine> 
     <OrderKey>COLGRE1-20140914-2345</OrderKey> 
     <ProductKey>1088</ProductKey> 
     <Qty>2</Qty> 
     <Free>0</Free> 
     <Cost>17.98</Cost> 
     <VAT_rate>0</VAT_rate> 
     <Details>Great Fairy Bake Off</Details> 
     <Class>Class 1</Class> 
     <Bags>5</Bags> 
     <Section>Funfare</Section> 
    </OrderLine> 
    <OrderLine> 
     <OrderKey>COLGRE1-20140914-2345</OrderKey> 
     <ProductKey>1123</ProductKey> 
     <Qty>1</Qty> 
     <Free>0</Free> 
     <Cost>3.99</Cost> 
     <VAT_rate>0</VAT_rate> 
     <Details>Space</Details> 
     <Class>Class 1</Class> 
     <Bags>5</Bags> 
     <Section>Funfare</Section> 
    </OrderLine> 
    <OrderLine> 
     <OrderKey>COLGRE1-20140914-2345</OrderKey> 
     <ProductKey>1001</ProductKey> 
     <Qty>2</Qty> 
     <Free>0</Free> 
     <Cost>25.98</Cost> 
     <VAT_rate>0</VAT_rate> 
     <Details>Friends Character Encyclopedia </Details> 
     <Class>Class 2</Class> 
     <Bags>4</Bags> 
     <Section>Funfare</Section> 
    </OrderLine> 
    <OrderLine> 
     <OrderKey>COLGRE1-20140914-2345</OrderKey> 
     <ProductKey>1002</ProductKey> 
     <Qty>1</Qty> 
     <Free>0</Free> 
     <Cost>9.99</Cost> 
     <VAT_rate>0</VAT_rate> 
     <Details>Winnie’s Big Bad Robot</Details> 
     <Class>Class 2</Class> 
     <Bags>4</Bags> 
     <Section>Funfare</Section> 
    </OrderLine> 
    <OrderLine> 
     <OrderKey>COLGRE1-20140914-2345</OrderKey> 
     <ProductKey>1012</ProductKey> 
     <Qty>1</Qty> 
     <Free>0</Free> 
     <Cost>6.50</Cost> 
     <VAT_rate>0</VAT_rate> 
     <Details>Snow</Details> 
     <Class>Class 2</Class> 
     <Bags>4</Bags> 
     <Section>Funfare</Section> 
    </OrderLine> 
    <OrderLine> 
     <OrderKey>COLGRE1-20140914-2345</OrderKey> 
     <ProductKey>1023</ProductKey> 
     <Qty>10</Qty> 
     <Free>0</Free> 
     <Cost>69.90</Cost> 
     <VAT_rate>0</VAT_rate> 
     <Details>The Witch with an Itch</Details> 
     <Class>Class 2</Class> 
     <Bags>4</Bags> 
     <Section>Funfare</Section> 
    </OrderLine> 
    <OrderLine> 
     <OrderKey>COLGRE1-20140914-2345</OrderKey> 
     <ProductKey>1333</ProductKey> 
     <Qty>2</Qty> 
     <Free>0</Free> 
     <Cost>19.98</Cost> 
     <VAT_rate>0</VAT_rate> 
     <Details>Scientriffic: Planet Earth</Details> 
     <Class>Class 2</Class> 
     <Bags>4</Bags> 
     <Section>Book Zone</Section> 
    </OrderLine> 
    </Order> 
</EmailOrders> 

XSLT :.

<?xml version="1.0"?> 
<xsl:stylesheet version="2.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:msxsl="urn:schemas-microsoft-com:xslt"> 
    <xsl:template match="/"> 
    <xsl:apply-templates select="EmailOrders/Order"/> 
    </xsl:template> 
    <xsl:template match="Order"> 
    <TABLE WIDTH="65%" BORDER="1" CELLPADDING="4" 
      bgcolor="yellow" align="center"> 
     <TR ALIGN="left"> 
     <TD>Customer message</TD> 
     <TD> 
      <xsl:value-of select="Customer_Msg"/> 
     </TD> 
     </TR> 
    </TABLE> 
    <BR/> 
    <BR/> 
    <TABLE WIDTH="100%" BORDER="1" CELLPADDING="4" 
      bgcolor="lightyellow" rules="cols" align="center"> 
     <xsl:choose> 
     <xsl:when test="Customer_Msg = 'Class sort' "> 
      <THEAD> 
      <TH>Class</TH> 
      <TH>List</TH> 
      <TH>Paid</TH> 
      <TH>Free</TH> 
      <TH>No.</TH> 
      <TH>Title</TH> 
      <TH>Price</TH> 
      </THEAD> 
      <xsl:for-each select="OrderLine"> 
      <xsl:sort select="Class"/> 
      <xsl:sort select="ProductKey"/> 
      <TR ALIGN="left"> 
       <TD> 
       <xsl:value-of select="Class"/> 
       </TD> 
       <TD> 
       <xsl:value-of select="Section"/> 
       </TD> 
       <TD> 
       <xsl:value-of select="Qty"/> 
       </TD> 
       <TD> 
       <xsl:value-of select="Free"/> 
       </TD> 
       <TD> 
       <xsl:value-of select="ProductKey"/> 
       </TD> 
       <TD> 
       <xsl:value-of select="Details"/> 
       </TD> 
       <TD> 
       <xsl:value-of select="Cost"/> 
       </TD> 
      </TR> 
      <xsl:if test="Class != following::Class[1] or position() = last()"> 
       <xsl:variable name="LastClass"> 
       <xsl:value-of select="Class"/> 
       </xsl:variable> 
       <TR ALIGN="left" bgcolor="lightblue"> 
       <TD> 
       <xsl:value-of select="$LastClass"/> Totals</TD> 
       <TD><xsl:value-of select="Bags"/> Bags</TD> 
       <TD> 
        <xsl:value-of select="sum(/EmailOrders 
             /Order/OrderLine 
             [Class=$LastClass]/Qty)"/> 
       </TD> 
       <TD> 
        <xsl:value-of select="sum(/EmailOrders 
             /Order/OrderLine 
             [Class=$LastClass]/Free)"/> 
       </TD> 
       <TD/> 
       <TD/> 
       <TD> 
        <xsl:value-of select="format-number(
             sum(
             /EmailOrders 
             /Order/OrderLine 
             [Class=$LastClass]/Cost), 
             '#####.##')"/> 
       </TD> 
       </TR> 
      </xsl:if> 
      </xsl:for-each> 
      <TR ALIGN="left" bgcolor="lightseagreen"> 
      <TD>Order totals</TD> 
      <TD/> 
      <TD> 
       <xsl:value-of select="sum(/EmailOrders 
            /Order/OrderLine/Qty)"/> 
      </TD> 
      <TD> 
       <xsl:value-of select="sum(/EmailOrders 
            /Order/OrderLine/Free)"/> 
      </TD> 
      <TD/> 
      <TD/> 
      <TD> 
       <xsl:value-of select="format-number(sum(/EmailOrders 
            /Order/OrderLine/Cost), 
            '#####.##')"/> 
      </TD> 
      </TR> 
     </xsl:when> 
     <xsl:otherwise> 
      <THEAD> 
      <TH>List</TH> 
      <TH>Paid</TH> 
      <TH>Free</TH> 
      <TH>Ref</TH> 
      <TH>Title</TH> 
      <TH>Total</TH> 
      </THEAD> 
      <xsl:for-each select="OrderLine"> 
      <xsl:sort select="ProductKey"/> 
      <TR ALIGN="left"> 
       <TD> 
       <xsl:value-of select="Section"/> 
       </TD> 
       <TD> 
       <xsl:value-of select="Qty"/> 
       </TD> 
       <TD> 
       <xsl:value-of select="Free"/> 
       </TD> 
       <TD> 
       <xsl:value-of select="ProductKey"/> 
       </TD> 
       <TD> 
       <xsl:value-of select="Details"/> 
       </TD> 
       <TD> 
       <xsl:value-of select="Cost"/> 
       </TD> 
      </TR> 
      <xsl:if test="Section != following::Section[1] 
          or position() = last()"> 
       <xsl:variable name="LastSection"> 
       <xsl:value-of select="Section"/> 
       </xsl:variable> 
       <TR ALIGN="left" bgcolor="lightblue"> 
       <TD> 
       <xsl:value-of select="Section"/> totals</TD> 
       <TD> 
        <xsl:value-of select="sum(/EmailOrders 
             /Order/OrderLine 
             [Section=$LastSection]/Qty)"/> 
       </TD> 
       <TD> 
        <xsl:value-of select="sum(/EmailOrders 
             /Order/OrderLine 
             [Section=$LastSection]/Free)"/> 
       </TD> 
       <TD/> 
       <TD/> 
       <TD> 
        <xsl:value-of select="format-number(
             sum(/EmailOrders 
             /Order/OrderLine 
             [Section=$LastSection] 
             /Cost), 
             '#####.##')"/> 
       </TD> 
       </TR> 
      </xsl:if> 
      </xsl:for-each> 
      <TR ALIGN="left" bgcolor="lightseagreen"> 
      <TD>Order totals</TD> 
      <TD> 
       <xsl:value-of select="sum(/EmailOrders 
            /Order/OrderLine/Qty)"/> 
      </TD> 
      <TD> 
       <xsl:value-of select="sum(/EmailOrders 
            /Order/OrderLine/Free)"/> 
      </TD> 
      <TD/> 
      <TD/> 
      <TD> 
       <xsl:value-of select="format-number(
            sum(/EmailOrders 
            /Order/OrderLine 
            /Cost), 
            '#####.##')"/> 
      </TD> 
      </TR> 
     </xsl:otherwise> 
     </xsl:choose> 
    </TABLE> 
    <BR/> 
    <BR/> 
    </xsl:template> 
</xsl:stylesheet> 
+0

스타일 시트는 버전 2.0은 말한다; XSLT 2.0 프로세서를 사용하고 있습니까? –

+0

그렇지 않을 수도 있습니다. 이 시트는 브라우저에서 열리고 인쇄 된 파일 일뿐입니다. 일반적으로 파이어 폭스 또는 IE9라고 생각합니다. – wingyip

+0

XSLT 2.0을 지원하는 브라우저가 없습니다. –

답변

1

문제는이 라인 (또는 Section 요소에 대한 비슷한 라인에 내려 오는

<xsl:if test="Class != following::Class[1] or position() = last()"> 

사용 following 축은 여기에 따라 달라지지 않습니다. Class 요소 이 (가) 정렬되었지만 원본 문서에있는 Class 요소의 순서. 이것이 문서를 다시 주문할 때 다른 결과를 얻는 이유입니다.

어떻게 해결할 수 있습니까? 음, 다른 접근법을 취할 필요가 있습니다. 이것은 실제로 그룹화 문제의 예입니다. XSLT 2.0에서는 그룹화가 XSLT 1.0보다 다르게 처리되기 때문에 사용할 수있는 XSLT 버전이 중요합니다.

스타일 시트에 version="2.0"이 지정되어 있지만 urn:schemas-microsoft-com:xslt도 사용하고 있으며 Microsoft는 XSLT 1.0을 좋아하지 않습니다. (당신은 XSLT 1.0 프로세서와 XSLT 2.0 스타일 시트를 실행할 수 있지만 그것은 단지 인식 할 수없는 명령 무시), 당신의 Class 요소의 순수 집중 Muenchian Grouping

이라는 기술을 사용 XSLT 1.0을 가정

을 이 답변의 목적은, 당신과 같이 키를 정의 할 :

<xsl:key name="OrderLine" match="OrderLine" use="Class" /> 

그런 다음, 각 그룹의 시작을 형성 그래서 같은 별개의 Class 요소를 얻을 것입니다 :

<xsl:for-each select="OrderLine[generate-id() = generate-id(key('OrderLine', Class)[1])]"> 
    <xsl:sort select="Class"/> 

그리고 그룹 (같은 클래스 즉, 모든 OrderLine 요소를 구성하는 OrderLine 요소를 얻을, 당신은이 작업을 수행 할 것입니다 :

<xsl:apply-templates select="key('OrderLine', Class)"> 
    <xsl:sort select="ProductKey"/> 
</xsl:apply-templates> 

key 기능은 또한의 총 합계를 사용할 수 수업.당신은 XSLT 2.0을 사용할 수있는 경우

당신은을 사용하는 대신 다음, 그래서

<xsl:for-each-group select="OrderLine" group-by="Class"> 

처럼 xsl:for-each-group 명령을 사용하여 수, 지금이 (매우 간단) XSLT

<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes" /> 

    <xsl:key name="OrderLine" match="OrderLine" use="Class" /> 

    <xsl:template match="/"> 
     <xsl:apply-templates select="EmailOrders/Order"/> 
    </xsl:template> 

    <xsl:template match="Order"> 
     <TABLE> 
     <THEAD> 
      <TH>Class</TH> 
      <TH>No.</TH> 
      <TH>Title</TH> 
      <TH>Price</TH> 
     </THEAD> 
     <xsl:for-each select="OrderLine[generate-id() = generate-id(key('OrderLine', Class)[1])]"> 
      <xsl:sort select="Class"/> 
      <xsl:apply-templates select="key('OrderLine', Class)"> 
       <xsl:sort select="ProductKey"/> 
      </xsl:apply-templates> 
      <TR> 
       <TD><xsl:value-of select="Class"/> Totals</TD> 
       <TD/> 
       <TD/> 
       <TD> 
        <xsl:value-of select="format-number(sum(key('OrderLine', Class)/Cost), '#####.##')"/> 
       </TD> 
      </TR> 
     </xsl:for-each> 
     <TR> 
      <TD>Totals</TD> 
      <TD/> 
      <TD/> 
      <TD> 
       <xsl:value-of select="format-number(sum(OrderLine/Cost), '#####.##')"/> 
      </TD> 
     </TR> 
     </TABLE> 
    </xsl:template> 

    <xsl:template match="OrderLine"> 
     <TR ALIGN="left"> 
      <TD><xsl:value-of select="Class"/></TD> 
      <TD><xsl:value-of select="ProductKey"/></TD> 
      <TD><xsl:value-of select="Details"/></TD> 
      <TD><xsl:value-of select="Cost"/></TD> 
     </TR> 
    </xsl:template> 
</xsl:stylesheet> 
시도 키를 사용하여 그룹의 항목을 가져 오려면 current-group 함수를 사용합니다. 예를

<xsl:apply-templates select="current-group()"> 
    <xsl:sort select="ProductKey"/> 
</xsl:apply-templates> 

과 유사 합에

<xsl:value-of select="format-number(sum(current-group()/Cost), '#####.##')"/> 
+0

이것은 스택 오버플로에서받은 최고의 답변이며 좋은 것들을 받았습니다. 매우 감사합니다. 분명히 첫 번째 제안을 사용하여 구현했습니다 :) – wingyip

관련 문제