2010-10-20 34 views
8

Hãy nói rằng tôi có một tài liệu xml như thế này:Sử dụng XSLT apply-templates có điều kiện chọn nút

<director> 
    <play> 
     <t>Nutcracker</t> 
     <a>Tom Cruise</a> 
    </play> 
    <play> 
     <t>Nutcracker</t> 
     <a>Robin Williams</a> 
    </play> 
    <play> 
     <t>Grinch Stole Christmas</t> 
     <a>Will Smith</a> 
    </play> 
    <play> 
     <t>Grinch Stole Christmas</t> 
     <a>Mel Gibson</a> 
    </play> 
</director> 

Bây giờ tôi muốn để có thể chọn tất cả các vở kịch với Will Smith là một diễn viên và định dạng lại nó vào một cái gì đó như thế này:

<Plays> 
    <Play title="Grinch Stole Christmas"> 
     <star>Will Smith</star> 
     <star>Mel Gibson</star> 
    </Play> 
</Plays> 

tôi chỉ muốn sử dụng apply-templates .. Không xsl: if hoặc cho mỗi vòng (tôi đã contrived ví dụ này là một phiên bản đơn giản của những gì tôi đang làm như vậy bạn có thể giúp tôi hiểu cách sử dụng xpath trong câu lệnh đối sánh)

Dưới đây là những gì tôi có cho đến nay:

<?xml version="1.0"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" indent="yes" /> 
     <xsl:template match="/director"> 
       <Plays> 
       <xsl:apply-templates select="play"/> 
       </Plays> 
     </xsl:template> 

     <xsl:template match="play[a='Will Smith']"> 
       <play title="{data(t)[1]}"> 
       <xsl:apply-templates select="a"/> 
       </play> 
     </xsl:template> 

     <xsl:template match="a"> 
       <star> 
       <xsl:value-of select="."/> 
       </star> 
     </xsl:template> 
</xsl:stylesheet> 

Về cơ bản tôi chỉ không chắc chắn làm thế nào để lọc ra các nút sử dụng XPath trong thuộc tính phù hợp của mẫu. Bất kỳ sự trợ giúp nào đều sẽ là tuyệt vời!

+0

Bạn đã làm gì cho đến nay? –

+0

Giải pháp dưới đây đã giải quyết được ... Cảm ơn bạn đã bình luận ít nhất :) – Msencenb

+0

Câu hỏi hay, +1. Xem câu trả lời của tôi cho hai giải pháp hiệu quả :) –

Trả lời

7

Điều kiện nên trên xsl: apply-templates thay vì xsl: template:

<Plays> 
    <xsl:apply-templates select="play[a='Will Smith']">"/> 
</Plays> 

Trong giải pháp của bạn, bạn đang chuyển ALL < chơi > nút. Đối với các nút phát khớp với điều kiện, mẫu của bạn được áp dụng. Nhưng đối với những người không phù hợp với điều kiện, một mẫu mặc định ("biến đổi danh tính") được áp dụng thay thế.

Ngoài ra, bạn có thể giữ cho tình trạng trên xsl: template match, nhưng thêm một mẫu cho < chơi > không phù hợp với điều kiện, chuyển đổi những < chơi > thành gì:

<xsl:template match="play[a='Will Smith']"> 
     <play title="{data(t)[1]}"> 
     <xsl:apply-templates select="a"/> 
     </play> 
    </xsl:template> 

    <xsl:template match="play"> 
    </xsl:template> 
+0

Cảm ơn bạn! Điều này hoạt động như một nét duyên dáng bây giờ – Msencenb

+0

@Msencenb: Điều này không xuất kết quả mong muốn. –

+0

Bạn có chắc chắn không? Ví dụ mã đầu tiên được đưa ra dường như làm việc cho tôi – Msencenb

1

stylesheet này :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:key name="kActorByTitle" match="a" use="../t"/> 
    <xsl:param name="pActor" select="'Will Smith'"/> 
    <xsl:template match="/"> 
     <Plays> 
      <xsl:apply-templates select="*/play[a=$pActor]"/> 
     </Plays> 
    </xsl:template> 
    <xsl:template match="play"> 
     <Play title="{t}"> 
      <xsl:apply-templates select="key('kActorByTitle',t)"/> 
     </Play> 
    </xsl:template> 
    <xsl:template match="a"> 
     <star> 
      <xsl:value-of select="."/> 
     </star> 
    </xsl:template> 
</xsl:stylesheet> 

Output:

<Plays> 
    <Play title="Grinch Stole Christmas"> 
     <star>Will Smith</star> 
     <star>Mel Gibson</star> 
    </Play> 
</Plays> 
+0

Điều này cũng hoạt động tốt và sử dụng các phím như câu trả lời khác. Tôi nghĩ rằng takeaway chính cho tôi là các điều kiện nên được trong lựa chọn chứ không phải là tuyên bố phù hợp – Msencenb

+0

@Msencenb: phù hợp với mô hình điều khiển so với chọn hướng là một vấn đề kéo vs đẩy phong cách. Cả hai đều ổn. Trong trường hợp này, vì tôi sử dụng tham số trong biểu định kiểu XSLT 1.0, tôi phải đi theo kiểu đẩy (tham chiếu param/var không được phép trong các mẫu XSLT 1.0) –

+0

@Alejandro, @@ Msencenb: Tham chiếu biến/tham số là được cho phép trong mẫu đối sánh trong XSLT 2.0 –

5

I. Có lẽ hiệu quả nhất XSLT 1.0 giải pháp:

<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:key name="kWSPlayByTitle" match="play[a='Will Smith']" 
    use="t"/> 

<xsl:key name="kActorByTitle" match="a" 
    use="../t"/> 

<xsl:template match="/"> 
    <Plays> 
    <xsl:apply-templates select= 
    "*/play[generate-id() 
      = 
      generate-id(key('kWSPlayByTitle',t)[1]) 
      ]"/> 
    </Plays> 
</xsl:template> 

<xsl:template match="play"> 
    <Play title="{t}"> 
    <xsl:apply-templates select="key('kActorByTitle',t)"/> 
    </Play> 
</xsl:template> 

<xsl:template match="a"> 
    <star><xsl:value-of select="."/></star> 
</xsl:template> 
</xsl:stylesheet> 

khi chuyển đổi này được áp dụng trên các tài liệu XML cung cấp:

<director> 
    <play> 
     <t>Nutcracker</t> 
     <a>Tom Cruise</a> 
    </play> 
    <play> 
     <t>Nutcracker</t> 
     <a>Robin Williams</a> 
    </play> 
    <play> 
     <t>Grinch Stole Christmas</t> 
     <a>Will Smith</a> 
    </play> 
    <play> 
     <t>Grinch Stole Christmas</t> 
     <a>Mel Gibson</a> 
    </play> 
</director> 

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

<Plays> 
    <Play title="Grinch Stole Christmas"> 
     <star>Will Smith</star> 
     <star>Mel Gibson</star> 
    </Play> 
</Plays> 

Do lưu ý:

  1. Hiệu quả đạt được bằng cách sử dụng các phím cả cho tất cả lượt, trong đó Mel Gibson đã tham gia và cho tất cả các diễn viên tham gia trong một định (tiêu đề) chơi.

  2. Thậm chí nếu tiêu đề trò chơi với Mel Gibson được liệt kê nhiều lần (do lỗi ngẫu nhiên, có lẽ ...) nó sẽ chỉ được liệt kê một lần trong kết quả.

II. Giải pháp XSLT 2.0 đơn giản và hiệu quả:

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

<xsl:template match="/*"> 
    <Plays> 
    <xsl:for-each-group select="play[a='Mel Gibson']" 
      group-by="t"> 
     <xsl:apply-templates select="."/> 
    </xsl:for-each-group> 
    </Plays> 
</xsl:template> 

<xsl:template match="play"> 
    <Play title="{t}"> 
    <xsl:for-each-group select="../play[t = current()/t]/a" 
     group-by="."> 
    <xsl:apply-templates select="."/> 
    </xsl:for-each-group> 
    </Play> 
</xsl:template> 

<xsl:template match="a"> 
    <star> 
    <xsl:value-of select="."/> 
    </star> 
</xsl:template> 
</xsl:stylesheet> 
+0

Tôi chưa bao giờ nghe đến các khóa ... nhưng điều này có vẻ hiệu quả nhất. Cảm ơn – Msencenb

+0

@Msencenb: Lưu ý rằng giải pháp XSLT 2.0 không sử dụng khóa nào cả. Vai trò của chúng được chơi bởi ''. Nhưng tất nhiên, ngay cả trong XSLT 2.0 nó cũng không đau, và quả thực có thể hữu ích, để biết cách sử dụng các khóa. –

+0

@Dimitre: Tôi không đi với hai phím vì biểu thức này '" */play [generate-id() ...] 'sẽ lặp lại trên tất cả các phần tử' play' dù sao đi nữa. –

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