2012-09-05 40 views
8

Tôi có một số XML được định dạng như sau:XSLT: Sắp xếp theo giá thấp hơn giữa 2 giá trị

<products> 
    <product> 
    <name>Product 1</name> 
    <price> 
     <orig>15</orig> 
     <offer>10</offer> 
    </price> 
    </product> 
    <product> 
    <name>Product 2</name> 
    <price> 
     <orig>13</orig> 
     <offer>12</offer> 
    </price> 
    </product> 
    <product> 
    <name>Product 3</name> 
    <price> 
     <orig>11</orig> 
    </price> 
    </product> 
</products> 

tôi cần phải sắp xếp các sản phẩm sử dụng XSLT 1.0 (trong tăng dần hoặc thứ tự giảm dần) dựa trên hiện tại của họ giá bán. Khó khăn của tôi nằm trong thực tế là tôi cần phải sắp xếp ở mức thấp hơn của hai giá trị có thể có giá trị <orig><offer>nếu cả hai đều tồn tại.

Đối với ví dụ trên thứ tự đúng sẽ là:

  • sản phẩm 1 (giá trị thấp nhất = 10)
  • sản phẩm 3 (giá trị thấp nhất = 11)
  • sản phẩm 2 (giá trị thấp nhất = 12)

Bất kỳ trợ giúp nào sẽ được đánh giá cao, vì tôi dường như không thể tìm thấy câu hỏi tương tự thông qua tìm kiếm.

Trả lời

5

I. Có một XSLT nói chung và tinh khiết 1.0 giải pháp - đơn giản như 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:strip-space elements="*"/> 

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

<xsl:template match="/*"> 
    <products> 
    <xsl:apply-templates select="*"> 
    <xsl:sort data-type="number" select= 
    "price/*[not(../* &lt; .)]"/> 
    </xsl:apply-templates> 
    </products> 
</xsl:template> 
</xsl:stylesheet> 

II.Nếu price có các trẻ khác ngoài offerorig - trong trường hợp này là giải pháp chung I. ở trên (cũng như hai câu trả lời khác cho câu hỏi này) không hoạt động chính xác.

Dưới đây là một giải pháp đúng cho trường hợp 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:strip-space elements="*"/> 

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

<xsl:template match="/*"> 
    <products> 
    <xsl:apply-templates select="*"> 
    <xsl:sort data-type="number" select= 
    "sum(price/orig[not(../offer &lt;= .)]) 
    + 
    sum(price/offer[not(../orig &lt; .)]) 
    "/> 
    </xsl:apply-templates> 
    </products> 
</xsl:template> 
</xsl:stylesheet> 

III. Nếu chúng ta biết rằng offer không bao giờ vượt quá orig:

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

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

<xsl:template match="/*"> 
    <products> 
    <xsl:apply-templates select="*"> 
    <xsl:sort data-type="number" 
     select="price/offer | price/orig[not(../offer)]"/> 
    </xsl:apply-templates> 
    </products> 
</xsl:template> 
</xsl:stylesheet> 

IV. Xác minh:

Cả ba biến đổi trên, khi áp dụng cho các tài liệu XML cung cấp:

<products> 
    <product> 
    <name>Product 1</name> 
    <price> 
     <orig>15</orig> 
     <offer>10</offer> 
    </price> 
    </product> 
    <product> 
    <name>Product 2</name> 
    <price> 
     <orig>13</orig> 
     <offer>12</offer> 
    </price> 
    </product> 
    <product> 
    <name>Product 3</name> 
    <price> 
     <orig>11</orig> 
    </price> 
    </product> 
</products> 

sản xuất mong muốn, đúng kết quả:

<products> 
    <product> 
     <name>Product 1</name> 
     <price> 
     <orig>15</orig> 
     <offer>10</offer> 
     </price> 
    </product> 
    <product> 
     <name>Product 3</name> 
     <price> 
     <orig>11</orig> 
     </price> 
    </product> 
    <product> 
     <name>Product 2</name> 
     <price> 
     <orig>13</orig> 
     <offer>12</offer> 
     </price> 
    </product> 
</products> 

Giải pháp II là duy nhất của ba vẫn tạo ra kết quả chính xác khi được áp dụng trên tài liệu XML này (đã thêm minAcceptable con vào price):

<products> 
    <product> 
    <name>Product 1</name> 
    <price> 
     <orig>15</orig> 
     <offer>10</offer> 
     <minAcceptable>8</minAcceptable> 
    </price> 
    </product> 
    <product> 
    <name>Product 2</name> 
    <price> 
     <orig>13</orig> 
     <offer>12</offer> 
     <minAcceptable>6</minAcceptable> 
    </price> 
    </product> 
    <product> 
    <name>Product 3</name> 
    <price> 
     <orig>11</orig> 
     <minAcceptable>7</minAcceptable> 
    </price> 
    </product> 
</products> 

Do lưu ý rằng không có câu trả lời khác xử lý tài liệu XML này một cách chính xác.

+0

+1 Rất thanh lịch - công việc tuyệt vời, @DimitreNovatchev. Tuy nhiên, tôi cho rằng Solution II không phù hợp với câu hỏi (vì nó giải quyết một tình huống không bao giờ được mô tả bởi OP) và do đó không nên được sử dụng làm bằng chứng về sự không đầy đủ trong các câu trả lời khác. :) – ABach

+0

@ABach, Bạn được chào đón. Đối với sự liên quan, cả giải pháp 1. và 3. đều chính xác theo tài liệu XML của OP. Giải pháp 2 cung cấp cho chúng tôi kiến ​​thức phải làm gì trong một tình huống hơi khác, khi giải pháp khác không hoạt động. Kiến thức là sức mạnh, bạn không thonk như vậy? –

+0

Tôi sẽ mua nó. :) – ABach

6

(Trả lời được cập nhật để bao gồm suy nghĩ về cả XSLT 1.0 và 2,0)

I. XSLT 1.0:

Lưu ý rằng XSLT 1.0 không có một built-in tương đương với min(); giả sử trình phân tích cú pháp của bạn hỗ trợ EXSLT, bạn có thể sử dụng chức năng math:min() để đạt được một giải pháp khá giống với biến thể XSLT 2.0 bên dưới.


II. XSLT 2.0:

Đây là giải pháp sử dụng hàm tổng hợp XPath 2.0 min().

Khi giải pháp này XSLT 2.0:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 
    <xsl:output omit-xml-declaration="no" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

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

    <xsl:template match="products"> 
    <products> 
     <xsl:apply-templates select="product"> 
     <xsl:sort select="min(price/offer|price/orig)" 
      data-type="number" order="ascending" /> 
     </xsl:apply-templates> 
    </products> 
    </xsl:template> 

</xsl:stylesheet> 

..is áp dụng cho XML cung cấp:

<products> 
    <product> 
    <name>Product 1</name> 
    <price> 
     <orig>15</orig> 
     <offer>10</offer> 
    </price> 
    </product> 
    <product> 
    <name>Product 2</name> 
    <price> 
     <orig>13</orig> 
     <offer>12</offer> 
    </price> 
    </product> 
    <product> 
    <name>Product 3</name> 
    <price> 
     <orig>11</orig> 
    </price> 
    </product> 
</products> 

..the muốn kết quả được sản xuất:

<?xml version="1.0" encoding="UTF-8"?> 
<products> 
    <product> 
     <name>Product 1</name> 
     <price> 
     <orig>15</orig> 
     <offer>10</offer> 
     </price> 
    </product> 
    <product> 
     <name>Product 3</name> 
     <price> 
     <orig>11</orig> 
     </price> 
    </product> 
    <product> 
     <name>Product 2</name> 
     <price> 
     <orig>13</orig> 
     <offer>12</offer> 
     </price> 
    </product> 
</products> 
+0

@MarkS - Tôi đã cập nhật câu trả lời của mình để cung cấp giải pháp XSLT 1.0 có thể có. Bạn có biết: trình phân tích cú pháp XSLT của bạn có triển khai các hàm mở rộng EXSLT không (hoặc, đặc biệt là tập con 'math' của các hàm đó)? – ABach

+0

. Có vẻ như đây có thể là giải pháp. Tôi sẽ có một vở kịch trước khi tôi đưa ra bất kỳ phản hồi nào. Cảm ơn nhiều! – MarkS

+0

@MarkS - âm thanh tốt; giữ cho chúng tôi được đăng! – ABach

5

Một giải pháp XSLT 1.0 mà không yêu cầu EXSLT:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output omit-xml-declaration="no" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

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

    <xsl:template match="products"> 
     <products> 
      <xsl:apply-templates select="product"> 
       <xsl:sort select="(price/*[not(. > ../*)])[1]" 
        data-type="number" order="ascending" /> 
      </xsl:apply-templates> 
     </products> 
    </xsl:template> 

</xsl:stylesheet> 
+0

+1 Giải pháp tuyệt vời. – ABach

Các vấn đề liên quan