2010-04-10 27 views
7

cho xml này:XSLT và XPath: trận đấu trước bình luận

<root> 
    <list> 
     <!-- foo's comment --> 
     <item name="foo" /> 
     <item name="bar" /> 
     <!-- another foo's comment --> 
     <item name="another foo" /> 
    </list> 
</root> 

Tôi muốn sử dụng một XPath để chọn tất cả các mục-node có một lời nhận xét ngay trước họ, có nghĩa là tôi thích để chọn các mục "foo" và "foo" khác chứ không phải mục "thanh".

Tôi đã bỏ qua về trục anh chị em trước đó và chức năng bình luận() nhưng không có kết quả.

+0

Lưu ý rằng trong mô hình dữ liệu XSLT/XPath những yếu tố mục bạn đang tìm kiếm một không ngay lập tức trước bởi một nút bình luận nhưng thay vì một nút văn bản với không gian màu trắng. Vì vậy, trừ khi bạn sử dụng '' trong bảng định kiểu của bạn, các nút văn bản không gian màu trắng này có thể cản trở bạn. –

+0

Câu hỏi hay (+1). Xem câu trả lời của tôi cho giải pháp hoàn chỉnh (hiện tại). Nhận xét của Martin Honnen là chính xác và mặc dù câu trả lời được chọn hiện tại có thể làm việc cho bạn, nhưng nó có thể đột ngột ngừng làm như vậy (nếu công cụ XPath được cung cấp với một tài liệu XML, mà các nút chỉ trắng không bị tước đi). –

Trả lời

3

Điều này dường như làm việc:

//comment()/following-sibling::*[1]/self::item 

Có vẻ cho ngay lập tức anh chị em ý kiến ​​đó cũng là <item> yếu tố sau. Tôi không biết cách nào tốt hơn để thể hiện phần ::*[1]/self::item, điều này thật xấu xí; lưu ý rằng nếu nó được viết ::item[1] thì nó cũng sẽ tìm thấy <item> s không phải ngay lập tức được xử lý bởi nhận xét.

+0

Điều gì sẽ xảy ra nếu có hướng dẫn xử lý giữa nhận xét và phần tử 'mục'? Chắc chắn là một trường hợp cạnh nhưng poster ban đầu đầu tiên cần phải làm rõ liệu một phần tử 'item' có trước một lệnh xử lý trước bởi một chú thích là một phần tử mà anh ta muốn chọn hay không. –

+0

@Kevin: Cảm ơn, Kevin.X-Path này đủ đơn giản để tôi nắm bắt và nó hoạt động hoàn hảo :) @Martin: May mắn thay, tôi là chủ nhân của đầu vào Xml, vì vậy tôi chắc chắn sẽ không có bất kỳ hướng dẫn xử lý nào. Cảm ơn anyway cho gợi ý hữu ích. – miasbeck

+0

Nhận xét của Martin Honnen là chính xác. –

0

Như đã đề cập trong this thread, giới thiệu một bài kiểm tra (<xsl:if test="..."></xsl:if>) như:

trước-sibling :: comment()

sẽ chỉ kiểm tra xem nút một anh chị em trước đó là một nhận xét.

Nếu bạn muốn biết, các anh chị em trước đó là những yếu tố hoặc ý kiến, cho dù gần một là một bình luận, bạn có thể thử:

(preceding-sibling::*|preceding-sibling::comment())[1][self::comment()] # WRONG 

NHƯNG: rằng sẽ không làm việc, bởi vì mặc dù "[1]" có nghĩa là đầu tiên theo hướng ngược cho preceding-sibling, nó không có nghĩa là cho một biểu thức trong ngoặc đơn - nó nghĩa đầu tiên trong thứ tự tài liệu

Bạn có thể thử:

(preceding-sibling::*|preceding-sibling::comment())[last()][self::comment()] 

hoặc

preceding-sibling::node()[self::*|self::comment()][1][self::comment()] 

Ví dụ:

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

    <xsl:template match="//item"> 
    <xsl:if test="preceding-sibling::node()[self::*|self::comment()][1][self::comment()]"> 
     <xsl:value-of select="./@name" /> 
    </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

sẽ chỉ hiển thị:

foo 
another foo 

khi gõ:

C:\Prog\xslt\preceding-sibling_comment> 
    java -cp ..\saxonhe9-2-0-6j\saxon9he.jar net.sf.saxon.Transform -s:test.xml -xsl:t.xslt -o:res.xml 

với:

  • test.xml: tập tin của bạn được hiển thị trong câu hỏi của bạn
  • t.xslt: file XSLT trên
  • res.xml: kết quả chuyển đổi tập tin

Chỉnh sửa: vì nó không đưa vào hướng dẫn xử lý tài khoản, tôi đã để lại câu trả lời đó dưới dạng Wiki cộng đồng.

+0

Cảm ơn bạn đã trả lời kỹ lưỡng VonC! Tôi đã thử cấu trúc "if" và nó hoạt động cho tôi. Tôi thích sử dụng các biểu hiện từ Kevin mặc dù, vì nó là cái gì tôi có thể hiểu (và hy vọng nhớ). – miasbeck

+0

Điều này không hoạt động trong tình huống được mô tả bởi Martin Honnen. –

+1

@Dimitre: +1 trên câu trả lời của bạn và tôi để tôi là Community Wiki. – VonC

3

Các giải pháp hiện đang được chọn:

//comment()/following-sibling::*[1]/self::item 

không hoạt động trong trường hợp có một hướng dẫn khi xử lý (hoặc một nhóm toàn bộ hướng dẫn xử lý) giữa các comment và nguyên tố này - như nhận thấy trong một bình luận của Martin Honnen.

Giải pháp dưới đây không có vấn đề như vậy.

Biểu thức XPath sau đây chọn chỉ các yếu tố nút được một trong hai ngay trước bởi một nút bình luận, hoặc ngay lập tức trước bởi một nút văn bản trắng-không gian duy nhất, mà là ngay lập tức trước bởi một nút bình luận:

(//comment() 
    /following-sibling::node() 
    [1] 
    [self::text() 
    and 
    not(normalize-space()) 
    ] 
     /following-sibling::node() 
      [1] [self::item] 
) 
| 
(//comment() 
    /following-sibling::node() 
    [1] 
    [self::item] 
) 

Dưới đây là một thử nghiệm hoàn chỉnh:

Chúng tôi sử dụng tài liệu XML này:

<root> 
    <list> 
     <!-- foo's comment --> 
     <item name="foo" /> 
     <item name="bar" /> 
     <!-- another foo's comment --> 
     <item name="another foo" /> 
     <!-- comment 3 --><item name="immed.after 3"/> 
     <!-- comment 4 --><?PI ?><item name="after PI"/> 
    </list> 
</root> 

Khi việc chuyển đổi sau đây được áp dụng trên các tài liệu trên XML:

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


<xsl:template match="/"> 
    <xsl:copy-of select= 
    " 
    (//comment() 
     /following-sibling::node() 
     [1] 
     [self::text() 
     and 
     not(normalize-space()) 
     ] 
      /following-sibling::node() 
       [1] [self::item] 
    ) 
    | 
    (//comment() 
     /following-sibling::node() 
     [1] 
     [self::item] 
    ) 
    "/> 
</xsl:template> 
</xsl:stylesheet> 

các truy nã, kết quả chính xác được sản xuất:

<item name="foo"/> 
<item name="another foo"/> 
<item name="immed.after 3"/> 
+0

Câu trả lời tốt và đầy đủ. +1 – VonC

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