2010-05-04 74 views
14

Đối với mỗi nút "đại lý", tôi cần phải tìm các phần tử "stmt" có cùng giá trị key1, key2, key3 và chỉ xuất một nút "stmt" với "comm" và Các giá trị "prem" được cộng lại với nhau. Đối với bất kỳ phần tử "stmt" nào trong "đại lý" đó không khớp với bất kỳ phần tử "stmt" nào khác dựa trên key1, key2 và key3, tôi cần xuất chúng như nguyên trạng. Vì vậy, sau khi chuyển đổi nút "đại lý" đầu tiên sẽ chỉ có hai nút "stmt" (một tổng hợp) và nút "đại lý" thứ hai sẽ được chuyển vì các khóa không khớp. Các giải pháp XSLT 1.0 hoặc 2.0 là ok ... mặc dù biểu định kiểu của tôi hiện là 1.0. Lưu ý rằng các nút đại lý có thể có bất kỳ số phần tử "stmt" nào có các phím phù hợp cần được nhóm và tổng hợp và bất kỳ số nào không.Cách nhóm và tổng giá trị trong XSLT

<statement> 
<agency> 
    <stmt> 
     <key1>1234</key1> 
     <key2>ABC</key2> 
     <key3>15.000</key3> 
     <comm>75.00</comm> 
     <prem>100.00</prem> 
    </stmt> 
    <stmt> 
     <key1>1234</key1> 
     <key2>ABC</key2> 
     <key3>15.000</key3> 
     <comm>25.00</comm> 
     <prem>200.00</prem> 
    </stmt> 
    <stmt> 
     <key1>1234</key1> 
     <key2>ABC</key2> 
     <key3>17.50</key3> 
     <comm>25.00</comm> 
     <prem>100.00</prem> 
    </stmt> 
</agency> 
<agency> 
    <stmt> 
     <key1>5678</key1> 
     <key2>DEF</key2> 
     <key3>15.000</key3> 
     <comm>10.00</comm> 
     <prem>20.00</prem> 
    </stmt> 
    <stmt> 
     <key1>5678</key1> 
     <key2>DEF</key2> 
     <key3>17.000</key3> 
     <comm>15.00</comm> 
     <prem>12.00</prem> 
    </stmt> 
</agency> 

+0

Câu hỏi hay (+1). Xem câu trả lời của tôi cho một giải pháp XSLT 1.0 hoàn chỉnh. –

Trả lời

10

Và một XSLT giải pháp 2.0:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
exclude-result-prefixes="xs" 
> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="agency"> 
    <agency> 
    <xsl:for-each-group select="stmt" group-by= 
    "concat(key1, '+', key2, '+', key3)"> 

    <stmt> 
     <xsl:copy-of select= 
     "current-group()[1]/*[starts-with(name(),'key')]"/> 

     <comm> 
     <xsl:value-of select="sum(current-group()/comm)"/> 
     </comm> 
     <prem> 
     <xsl:value-of select="sum(current-group()/prem)"/> 
     </prem> 
    </stmt> 
    </xsl:for-each-group> 
    </agency> 
</xsl:template> 
</xsl:stylesheet> 
+0

'concat (key1, key2, key3)' sẽ bị lỗi trong một số trường hợp nhất định, ví dụ: 'key1 =" 1A "key2 =" B "key3 =" 1.000 "' và 'key1 =" 1 "key2 =" AB "key3 =" 1.000 "' ... Tôi cảm thấy rằng các chuỗi nối mà không có kiến ​​thức thân mật về nội dung của chúng (hoặc hạn chế) là sai. – Lucero

+0

@Lucero: Cảm ơn một lần nữa, không có gì sai với concat - đó là một cái gì đó trượt từ tôi - Tôi cảm thấy buồn ngủ cả ngày hôm nay - mà bây giờ đã được sửa chữa. Xin vui lòng, hãy cho tôi biết nếu sự điều chỉnh thỏa mãn bạn. Điều chỉnh này là một cái gì đó điển hình trong các loại giải pháp như vậy. –

+0

@Dimitre, trái ngược với vấn đề 'concat' khác' + 'không phải là một dấu tách thích hợp ở đây, vì dữ liệu XML về mặt lý thuyết có thể có các chuỗi khóa với' + 'trong chúng - nghĩ về' key1 = "1 + "key2 =" 2 "' và 'key1 =" 1 "key2 =" + 2 "'.Vì vậy, câu nói của tôi là bạn chỉ nên concat khi bạn biết rằng separator sẽ không bao giờ là một phần của dữ liệu được ghép nối. – Lucero

7

Trong XSLT 1.0 sử dụng phương pháp Muenchian cho nhóm (với chìa khóa hợp chất).

chuyển đổi này:

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

<xsl:key name="kStmtByKeys" match="stmt" 
     use="concat(generate-id(..), key1, '+', key2, '+', key3)"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="agency"> 
    <agency> 
    <xsl:for-each select= 
    "stmt[generate-id() 
      = 
      generate-id(key('kStmtByKeys', 
          concat(generate-id(..), key1, '+', key2, '+', key3) 
          )[1] 
         ) 
      ] 
    "> 
     <xsl:variable name="vkeyGroup" select= 
     "key('kStmtByKeys', concat(generate-id(..), key1, '+', key2, '+', key3))"/> 

    <stmt> 
     <xsl:copy-of select="*[starts-with(name(), 'key')]"/> 
     <comm> 
     <xsl:value-of select="sum($vkeyGroup/comm)"/> 
     </comm> 
     <prem> 
     <xsl:value-of select="sum($vkeyGroup/prem)"/> 
     </prem> 
    </stmt> 
    </xsl:for-each> 
    </agency> 
</xsl:template> 
</xsl:stylesheet> 

khi áp dụng trên tài liệu XML được cung cấp, sản xuất các kết quả mong muốn:

<statement> 
    <agency> 
     <stmt> 
      <key1>1234</key1> 
      <key2>ABC</key2> 
      <key3>15.000</key3> 
      <comm>100</comm> 
      <prem>300</prem> 
     </stmt> 
     <stmt> 
      <key1>1234</key1> 
      <key2>ABC</key2> 
      <key3>17.50</key3> 
      <comm>25</comm> 
      <prem>100</prem> 
     </stmt> 
    </agency> 
    <agency> 
     <stmt> 
      <key1>5678</key1> 
      <key2>DEF</key2> 
      <key3>15.000</key3> 
      <comm>10</comm> 
      <prem>20</prem> 
     </stmt> 
     <stmt> 
      <key1>5678</key1> 
      <key2>DEF</key2> 
      <key3>17.000</key3> 
      <comm>15</comm> 
      <prem>12</prem> 
     </stmt> 
    </agency> 
</statement> 
+0

Nếu tôi hiểu câu hỏi một cách chính xác, giải pháp của bạn bị hỏng khi một đại lý khác có các nút 'stmt' có cùng khóa. Đối với tôi có vẻ như là vì có nhiều cơ quan, phương pháp muenchian với khóa toàn cầu sẽ không hoạt động. – Lucero

+0

@Lucero: Quan sát tốt, cảm ơn. Điều này hiện đã được sửa và tôi vẫn đang sử dụng phương thức Muenchian với khóa compond. –

+0

Hm, đây có phải là cách tạo ra một khóa hợp chất đảm bảo mang lại kết quả mong muốn trong mọi tình huống không? nếu một khóa là 'concat ('1', '23')' và một khóa khác là 'concat ('12 ',' 3 ')' (bạn có ý tưởng), điều này có thể gây ra vấn đề tùy thuộc vào tài liệu đầu vào và bộ xử lý XSLT . – Lucero

1
<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="/|*"> 
     <xsl:copy> 
      <xsl:apply-templates select="*" /> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="stmt"> 
     <xsl:variable name="stmtGroup" select="../stmt[(key1=current()/key1) and (key2=current()/key2) and (key3=current()/key3)]" /> 
     <xsl:if test="generate-id()=generate-id($stmtGroup[1])"> 
      <xsl:copy> 
       <key1> 
        <xsl:value-of select="key1"/> 
       </key1> 
       <key2> 
        <xsl:value-of select="key2"/> 
       </key2> 
       <key3> 
        <xsl:value-of select="key3"/> 
       </key3> 
       <comm> 
        <xsl:value-of select="format-number(sum($stmtGroup/comm), '#.00')"/> 
       </comm> 
       <prem> 
        <xsl:value-of select="format-number(sum($stmtGroup/prem), '#.00')"/> 
       </prem> 
      </xsl:copy> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 
Các vấn đề liên quan