2011-08-19 34 views
7

Tôi có một cấu trúc tương tự như sau:XPath: Chọn nút nhưng không phải yếu tố con cụ

<page id='1'> 
    <title>Page 1</title>  
    <page id='2'> 
    <title>Sub Page 1</title> 
    </page> 
    <page id='3'> 
    <title>Sub Page 2</title> 
    </page>  
</page> 
<page id='4'> 
    <title>Page 2</title> 
</page> 

tôi cần phải chọn một trang bằng cách Id nhưng nếu trang đó có các trang hậu duệ Tôi không muốn quay trở lại những yếu tố đó, nhưng tôi muốn các yếu tố khác của trang đó. Nếu tôi chọn Trang 1 Tôi muốn trả lại tiêu đề nhưng không phải là trang con ...

//page[@id=1] 

Ở trên tôi được trang 1, nhưng làm cách nào để loại trừ các trang phụ? Ngoài ra, Có thể có bất kỳ số lượng phần tử tùy ý nào trong một trang.

//page[@id=1]/*[not(self::page)] 

Tôi nhận thấy rằng điều này giúp tôi có được dữ liệu tôi muốn. Tuy nhiên, dữ liệu đó trở lại dưới dạng một mảng các đối tượng với một đối tượng trên mỗi phần tử và dường như loại trừ các tên phần tử ???. Tôi đang sử dụng PHP SimpleXML cho những gì nó có giá trị.

+0

Tốt câu hỏi, 1. Xem câu trả lời của tôi cho một giải pháp ngắn và đơn giản. :) –

+1

"Tuy nhiên, dữ liệu đó trở lại dưới dạng một mảng các đối tượng với một đối tượng trên mỗi phần tử". Làm thế nào là khác với những gì bạn muốn/cần? – LarsH

+0

Dữ liệu trở lại theo một định dạng khác tùy thuộc vào truy vấn xpath, tôi nhận được một mảng SimpleXMLElement với một chuỗi duy nhất trong mỗi và thiếu các tên phần tử. Trường hợp đầu tiên trả về một đối tượng SimpleXMLElement đơn lẻ với tất cả các cặp giá trị khóa dự kiến. Tôi không hiểu tại sao, có lẽ tôi sẽ mở một câu hỏi khác. – Ben

Trả lời

7

Sử dụng:

//page[@id=$yourId]/node()[not(self::page)] 

này sẽ chọn tất cả các nút mà không phải là page và đó là con của bất kỳ page trong tài liệu, giá trị chuỗi có thuộc tính id bằng với chuỗi có trong $yourId (hầu hết bạn có thể thay thế $yourId ở trên bằng một chuỗi cụ thể, mong muốn, chẳng hạn như '1').

Đây là một XSLT đơn giản dựa trên xác minh:

<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:param name="pId" select="3"/> 

<xsl:template match="/"> 
    <xsl:copy-of select="//page[@id=$pId]/node()[not(self::page)]"/> 
</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 (bọc trong một nút đầu duy nhất để làm cho nó tốt được hình thành):

<pages> 
    <page id='1'> 
     <title>Page 1</title> 
     <page id='2'> 
      <title>Sub Page 1</title> 
     </page> 
     <page id='3'> 
      <title>Sub Page 2</title> 
     </page> 
    </page> 
    <page id='4'> 
     <title>Page 2</title> 
    </page> 
</pages> 

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

<title>Sub Page 2</title> 

Do lưu ý: Một giả định đã là một giá trị id xác định duy nhất một page. Nếu không phải như vậy, biểu thức XPath được đề xuất sẽ chọn tất cả các thành phầnpage có thuộc tính id có một chuỗi valu là $yourId.

Nếu trường hợp này xảy ra và chỉ một thành phần page phải được chọn, OP phải chỉ định một trong nhiều thành phần page với số id này sẽ được chọn.

Ví dụ, nó có thể là đầu tiên:

(//page[@id=$yourId]/node()[not(self::page)])[1] 

hay người cuối cùng:

(//page[@id=$yourId]/node()[not(self::page)])[last()] 

hay ...

+0

Trong khi điều này có vẻ chính xác, nó không thực sự làm việc .. Tôi không chắc chắn nếu có điều gì đó sai với xpath trong xml đơn giản của PHP, nhưng điều này trả về nhiều bản sao của trang được yêu cầu ??? – Ben

+0

@Ben: Điều này có thể xảy ra chỉ khi nhiều hơn một 'trang' có thể có cùng giá trị thuộc tính' id' của nó. Tôi đã cập nhật câu trả lời của mình để đề cập đến trường hợp này. Tôi cũng cung cấp một xác minh đơn giản cho thấy biểu thức XPath ban đầu chọn chính xác một phần tử 'page' nếu giá trị' id' xác định duy nhất một 'trang'. –

1

Nếu bạn chỉ quan tâm đến các yếu tố tiêu đề, điều này sẽ làm việc:

//page[@id=1]/title 

Tuy nhiên, nếu bạn cần các yếu tố phụ khác của trang, tôi không chắc chắn XPath là công cụ phù hợp với bạn. Âm thanh giống như một cái gì đó mà một XSLT sẽ phù hợp cho, vì những gì bạn đang thực sự làm là chuyển đổi dữ liệu của bạn.

+0

Thật không may tôi cần bất kỳ số lượng các yếu tố tùy ý ngoại trừ trang ... – Ben

+0

Cập nhật câu trả lời với thông tin thêm. Cảm thấy tự do để upvote nếu nó hữu ích trong anyway. :) –

+0

Cảm ơn, tôi bắt đầu nghĩ rằng Xpath có lẽ không thể làm điều này. Tôi luôn có thể viết một cái gì đó để xử lý dữ liệu tôi muốn nhưng hy vọng sẽ làm điều đó ở cấp dữ liệu. – Ben

0

Nếu trang luôn có một cái tên:

//page[@id='1']/*[not(boolean(./title))] 
Các vấn đề liên quan