2010-08-06 1 views
18

javadoc cho lớp Document có ghi chú sau theo getElementById.Java XML DOM: id Thuộc tính đặc biệt như thế nào?

Lưu ý: Các thuộc tính với tên "ID" hoặc "id" không loại trừ ID để định nghĩa

Vì vậy, tôi đọc một doc XHTML vào DOM (sử dụng Xerces 2.9.1) .

Tài liệu có một số cũ là <p id='fribble'> trong đó.

Tôi gọi getElementById("fribble") và trả về giá trị rỗng.

Tôi sử dụng XPath để nhận "// * [id = 'fribble']" và tất cả đều tốt.

Vì vậy, câu hỏi đặt ra là, nguyên nhân gây ra việc DocumentBuilder thực sự đánh dấu các thuộc tính ID là 'được xác định như vậy?'

Trả lời

16

Để gọi getElementById() hoạt động, số Document phải biết loại nút của nút và nút đích phải thuộc loại ID XML để tìm phương thức. Nó biết về các loại phần tử của nó thông qua một lược đồ liên quan. Nếu lược đồ không được đặt hoặc không khai báo thuộc tính id thuộc loại ID XML, getElementById() sẽ không bao giờ tìm thấy nó.

Đoán của tôi là tài liệu của bạn không biết thuộc tính id của phần tử là thuộc loại ID XML (có phải không?). Bạn có thể điều hướng đến nút trong DOM bằng cách sử dụng getChildNodes() và các hàm truyền tải DOM khác và thử gọi Attr.isId() trên thuộc tính id để chắc chắn.

Từ getElementById javadoc:

Việc thực hiện DOM dự kiến ​​sẽ sử dụng thuộc tính Attr.isId để xác định nếu một thuộc tính là loại ID.

Lưu ý: Thuộc tính có tên "ID" hoặc "id" không thuộc loại ID trừ khi được định nghĩa .

Nếu bạn đang sử dụng một DocumentBuilder để phân tích XML của bạn thành một DOM, hãy chắc chắn để gọi setSchema(schema) trên DocumentBuilderFactory trước khi gọi newDocumentBuilder(), để đảm bảo rằng những người xây dựng bạn nhận được từ các nhà máy là nhận thức của các loại nguyên tố .

4

Thuộc tính ID không phải thuộc tính có tên là "ID", thuộc tính được khai báo là thuộc tính ID theo DTD hoặc lược đồ. Ví dụ, html 4 DTD mô tả nó:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
3

Khái niệm xpath tương ứng thực sự sẽ là id('fribble'), mà phải trả lại kết quả tương tự như getElementById. Để làm việc này, dtd hoặc lược đồ được liên kết với tài liệu của bạn phải khai báo thuộc tính là kiểu ID.

Nếu bạn kiểm soát được xml được truy vấn, bạn cũng có thể thử đổi tên thuộc tính thành xml:id theo http://www.w3.org/TR/xml-id/.

47

Các thuộc tính này đặc biệt vì loại và không phải vì tên của chúng.

ID trong XML

Mặc dù nó rất dễ dàng để nghĩ về các thuộc tính như name="value" với giá trị được trở thành một chuỗi đơn giản, đó không phải là toàn bộ câu chuyện - đó cũng là một loại thuộc tính gắn liền với thuộc tính.

Điều này dễ dàng đánh giá cao khi có một Lược đồ XML có liên quan, vì Lược đồ XML hỗ trợ các kiểu dữ liệu cho cả các phần tử XML và các thuộc tính XML. Các thuộc tính XML được định nghĩa là một kiểu đơn giản (ví dụ: xs: string, xs: integer, xs: dateTime, xs: anyURI). Các thuộc tính đang được thảo luận ở đây được xác định với xs:ID kiểu dữ liệu dựng sẵn (xem section 3.3.8 of the XML Schema Part 2: Datatypes).

<xs:element name="foo"> 
    <xs:complexType> 
    ... 
    <xs:attribute name="bar" type="xs:ID"/> 
    ... 
    </xs:complexType> 
</xs:element> 

Mặc dù DTD không hỗ trợ kiểu dữ liệu phong phú về XML Schema, nó hỗ trợ một tập hạn chế về kiểu thuộc tính (được định nghĩa trong section 3.3.1 of XML 1.0). Các thuộc tính đang được thảo luận ở đây được xác định với loại thuộc tính của ID.

<!ATTLIST foo bar ID #IMPLIED> 

Với lược đồ XML ở trên hoặc DTD, phần tử sau sẽ được xác định bằng giá trị ID của "xyz".

<foo bar="xyz"/> 

Mà không biết Schema XML hoặc DTD, không có cách nào để nói với một ID là gì và những gì không:

  • Thuộc tính với tên của "id" không nhất thiết phải có một loại thuộc tính ID; và
  • Thuộc tính có tên không phải là "id" có thể có loại thuộc tính của ID!

Để cải thiện tình trạng này, sau đó xml:id được phát minh (xem xml:id W3C Recommendation). Đây là thuộc tính luôn có cùng tiền tố và tên và được coi là thuộc tính với loại thuộc tính ID. Tuy nhiên, cho dù nó sẽ phụ thuộc vào phân tích cú pháp được sử dụng là nhận thức của xml:id hay không. Vì nhiều trình phân tích cú pháp ban đầu được viết trước khi xml:id được xác định, nó có thể không được hỗ trợ.

ID trong Java

Trong Java, getElementById() tìm thấy yếu tố bằng cách tìm kiếm các thuộc tính của loại ID, không cho các thuộc tính với tên của "id".

Trong ví dụ trên, getElementById("xyz") sẽ trở lại mà foo yếu tố, mặc dù tên của thuộc tính trên nó không phải là "id" (giả sử DOM biết rằng bar có một loại thuộc tính ID).

Vậy làm thế nào để DOM biết loại loại thuộc tính thuộc tính nào? Có ba cách:

  1. Cung cấp một XML Schema để phân tích cú pháp (example)
  2. Cung cấp một DTD để phân tích cú pháp
  3. Rõ ràng chỉ vào DOM rằng nó được coi là một loại thuộc tính của ID.

Lựa chọn thứ ba được thực hiện bằng cách sử dụng setIdAttribute() hoặc setIdAttributeNS() hoặc setIdAttributeNode() phương pháp trên org.w3c.dom.Element class.

Document doc; 
Element fooElem; 

doc = ...; // load XML document instance 
fooElem = ...; // locate the element node "foo" in doc 

fooElem.setIdAttribute("bar", true); // without this, 'found' would be null 

Element found = doc.getElementById("xyz"); 

Điều này phải được thực hiện cho mỗi nút phần tử có một trong các loại thuộc tính này trên chúng. Không có phương thức tích hợp đơn giản nào để làm cho tất cả các lần xuất hiện của thuộc tính với tên đã cho (ví dụ: "id") là loại thuộc tính ID.

Cách tiếp cận thứ ba này chỉ hữu ích trong các tình huống trong đó mã gọi getElementById() tách biệt với việc tạo DOM. Nếu đó là cùng một mã, nó đã tìm thấy phần tử để thiết lập thuộc tính ID sao cho nó không có khả năng cần gọi getElementById().

Ngoài ra, hãy lưu ý rằng các phương pháp đó không nằm trong đặc tả DOM gốc. getElementById được giới thiệu trong DOM level 2.

ID trong XPath

XPath trong câu hỏi ban đầu đã cho kết quả một vì nó chỉ phù hợp với các thuộc tính tên.

Để phù hợp trên loại giá trị ID thuộc tính, hàm XPath id cần phải được sử dụng (nó là một trong những Node Set Functions from XPath 1.0):

id("xyz") 

Nếu đó đã được sử dụng, XPath sẽ trao kết quả tương tự như getElementById() (tức là không tìm thấy kết quả phù hợp).

ID trong XML tiếp tục

Hai tính năng quan trọng của ID nên được đánh dấu.

Thứ nhất, giá trị của tất cả các thuộc tính của loại thuộc tính ID phải là duy nhất cho toàn bộ tài liệu XML. Trong ví dụ sau, nếu personIdcompanyId cả hai đều có loại thuộc tính ID, sẽ là lỗi khi thêm một công ty khác với companyId của id24601, bởi vì nó sẽ trùng lặp với giá trị ID hiện tại. Mặc dù tên thuộc tính khác nhau, nhưng nó là loại thuộc tính quan trọng.

<test1> 
<person personId="id24600">...</person> 
<person personId="id24601">...</person> 
<company companyId="id12345">...</company> 
<company companyId="id12346">...</company> 
</test1> 

Thứ hai, thuộc tính được định nghĩa trên các yếu tố chứ không phải là toàn bộ tài liệu XML. Vì vậy, các thuộc tính có cùng tên thuộc tính trên các phần tử khác nhau có thể có các thuộc tính thuộc tính khác nhau thuộc tính. Trong tài liệu ví dụ XML sau đây, nếu chỉ alpha/@bar có một loại thuộc tính của ID (và không có thuộc tính khác là), getElementById("xyz") sẽ trở lại một yếu tố, nhưng getElementById("abc") sẽ không (kể từ beta/@bar không phải là của loại thuộc tính ID). Ngoài ra, không phải là lỗi đối với thuộc tính gamma/@bar để có cùng giá trị với alpha/@bar, giá trị đó không được xem xét tính duy nhất của ID trong tài liệu XML vì nó không phải là loại thuộc tính ID.

<test2> 
    <alpha bar="xyz"/> 
    <beta bar="abc"/> 
    <gamma bar="xyz"/> 
</test2> 
+0

+1 Nice câu trả lời! Tôi đã học được một cái gì đó mới ngày hôm nay. –

+0

Thật không may, liên kết đến ví dụ lược đồ đã chết ngay bây giờ. – ferkulat

1

Sau đây sẽ cho phép bạn để có được một phần tử bằng cách id:

public static Element getElementById(Element rootElement, String id) 
{ 
    try 
    { 
     String path = String.format("//*[@id = '%1$s' or @Id = '%1$s' or @ID = '%1$s' or @iD = '%1$s' ]", id); 
     XPath xPath = XPathFactory.newInstance().newXPath(); 
     NodeList nodes = (NodeList)xPath.evaluate(path, rootElement, XPathConstants.NODESET); 

     return (Element) nodes.item(0); 
    } 
    catch (Exception e) 
    { 
     return null; 
    } 
}