Sử dụng đối tượng NamespaceContext của ngôn ngữ Java với XPath

Các phương thức để phân tích các không gian tên với API của Java

Nếu bạn muốn dùng các không gian tên trong các biểu thức XPath, bạn phải cung cấp đường dẫn của tiền tố được sử dụng cho URI của không gian tên. Bài viết này mô tả ba biến thể của việc cung cấp tiền tố cho ánh xạ không gian tên. Bài này có các đoạn mã mẫu giúp bạn dễ dàng viết mã cho NamespaceContext.

Holger Kraus, Chuyên gia IT, IBM

Holger tốt nghiệp khoa toán trường đại học Bonn ở Đức. Từ năm 1996, anh ta đã làm việc ở IBM Global Business Services và phát triển các giải pháp cho các khách hàng trên các trang của khách hàng. Kinh nghiệm của anh ta về XPath và lập trình Java có được từ việc sử dụng các kỹ thuật này trong các dự án của anh ta



17 07 2009

Điều kiện tiên quyết và ví dụ

Trong bài này, tôi giả sử rằng bạn đã quen với các chi tiết kỹ thuật được mô tả trong "Đánh giá XPath từ nền tảng Java™" do Brett McLaughlin viết. Nếu bạn chưa biết cách thực thi các chương trình Java sử dụng XPath, xin vui lòng tham khảo bài viết của Brett (tìm thấy ở Tài nguyên.) Và bạn cũng đã biết các hàm API cần thiết để đọc tệp XML và để đánh giá biểu thức XPath.

Bạn sẽ dùng tệp XML sau cho tất cả các ví dụ trong bài:

Ví dụ 1. Tệp XML mẫu
<?xml version="1.0" encoding="UTF-8"?>

<books:booklist
  xmlns:books="http://univNaSpResolver/booklist"
  xmlns="http://univNaSpResolver/book"
  xmlns:fiction="http://univNaSpResolver/fictionbook">
  <science:book xmlns:science="http://univNaSpResolver/sciencebook">
    <title>Learning XPath</title>
    <author>Michael Schmidt</author>
  </science:book>
  <fiction:book>
    <title>Faust I</title>
    <author>Johann Wolfgang von Goethe</author>
  </fiction:book>
  <fiction:book>
    <title>Faust II</title>
    <author>Johann Wolfgang von Goethe</author>
  </fiction:book>
</books:booklist>

Mẫu XML này có ba không gian tên (namespace) được khai báo trong thành phần gốc và một cái được khái báo trong thành phần con. Bạn sẽ thấy sự khác biệt từ ví dụ này.

Các từ viết tắt hay dùng

  • API: Giao diện lập trình ứng dụng
  • DOM: Mô hình đối tượng tài liệu
  • URI: Định danh tài nguyên tổng quát
  • XHTML: Ngôn ngữ đánh dấu siêu văn bản mở rộng
  • XML: Ngôn ngữ đánh dấu mở rộng
  • XSD: Định nghĩa lược đồ XML
  • XSLT: Chuyển đổi ngôn ngữ định kiểu mở rộng

Điều thú vị thứ hai về XML mẫu này là thành phần booklist có ba thành phần con, tất cả có tên là book. Nhưng thành phần con đầu tiên có không gian tên là science, trong khi thành phần con khác có không gian tên là fiction. Điều này có nghĩa là, những thành phần này là khác nhau đối với XPath. Bạn sẽ thấy các hệ quả trong các ví dụ tiếp theo.

Cũng cần phải nói trước, đoạn mã không được tối ưu hóa cho việc bảo trì nhưng nó dễ đọc. Có nghĩa là nó có một số chỗ dư thừa. Kết quả được đưa ra bằng cách đơn giản nhất thông qua System.out.println(). Tất cả các dòng của đoạn mã liên quan đến kết quả được viết tắt với '...' trong bài viết. Tôi cũng không đề cập đến phương thức trợ giúp (helper) trong bài này, nhưng chúng đi kèm trong tệp tải về (Xem Tải về).

Nền tảng lý thuyết

Ý nghĩa của các không gian tên là gì và tại sao phải quan tâm tới chúng? Một không gian tên là một phần của định danh cho một thành phần hay thuộc tính. Bạn có thể có các thành phần hoặc thuộc tính với cùng tên cục bộ, nhưng khác không gian tên. Chúng khác nhau hoàn toàn. Xem ví dụ ở trên (science:bookfiction:book). Bạn cần các không gian tên để phân tích xung đột tên nếu bạn bạn kết hợp các tệp XML từ các nguồn khác nhau. Lấy một tệp XSLT làm ví dụ. Nó bao gồm các thành phần của không gian tên XSLT, các thành phần từ không gian tên của chính bạn, và (thường thì) các thành phần của không gian tên XHTML. Bằng cách sử dụng các không gian tên bạn có thể tránh sự nhập nhằng khó hiểu liên quan đến các thành phần có cùng tên địa phương.

Không gian tên được xác định bởi URI (trong ví dụ này, http://univNaSpResolver/booklist). Để tránh việc sử dụng chuỗi dài như thế, bạn định nghĩa một tiền tố (prefix) mà gắn với URI này (trong ví dụ này, books). Xin nhớ rằng tiền tố cũng giống như một biến: tên của nó không thành vấn đề. Nếu hai tiền tố cùng tham chiếu tới một URI, không gian tên của các thành phần gắn với tiền tố sẽ giống nhau (xem ví dụ 1 trong Ví dụ 5).

Một biểu thức XPath sử dụng các tiền tố (ví dụ, books:booklist/science:book) và, bạn phải cung cấp URI gắn với mỗi tiền tố. Đây là nơi mà NamespaceContext xuất hiện. Nó làm những việc đó.

Bài viết này giải thích các cách khác nhau để cung cấp ánh xạ giữa tiền tố và URI.

Trong tệp XML, ánh xạ được cung cấp bởi thuộc tính xmlns như: xmlns:books="http://univNaSpResolver/booklist" hoặc xmlns="http://univNaSpResolver/book" (không gian tên mặc định).

Sự cần thiết của việc cung cấp sự phân giải không gian tên

Nếu bạn có XML mà sử dụng các không gian tên, một biểu thức XPath sẽ thất bại nếu bạn không cung cấp một NamespaceContext. Ví dụ 0 trong Ví dụ 2 minh họa trường hợp này. Đối tượng XPath được xây dựng và ước lượng trên tài liệu XML. Đầu tiên, thử viết biểu thức mà không có các tiền tố không gian tên (result1). Trong phần hai, viết biểu thức với các tiền tố không gian tên result2).

Ví dụ 2. Ví dụ 0 mà không có sự phân giải không gian tên
    private static void example0(Document example)
            throws XPathExpressionException, TransformerException {
        sysout("\n*** Zero example - no namespaces provided ***");

        XPath xPath = XPathFactory.newInstance().newXPath();

...
        NodeList result1 = (NodeList) xPath.evaluate("booklist/book", example,
                XPathConstants.NODESET);
...
        NodeList result2 = (NodeList) xPath.evaluate(
                "books:booklist/science:book", example, XPathConstants.NODESET);
...
    }

Kết quả như sau.

Ví dụ 3. Kết quả từ ví dụ 0
*** Zero example - no namespaces provided ***
First try asking without namespace prefix:
--> booklist/book
Result is of length 0
Then try asking with namespace prefix:
--> books:booklist/science:book
Result is of length 0
The expression does not work in both cases.

Trong cả hai trường hợp, sự ước lượng XPath không trả lại bất cứ nốt nào và không có ngoại lệ. XPath không thể tìm thấy nút nào bởi vì ánh xạ của các tiền tố tới các URI bị thiếu.

Sự phân giải không gian tên được viết sẵn trong mã

Hoàn toàn có thể cung cấp các không gian tên như là các giá trị có sẵn trong mã cái mà trông giống như lớp trong Ví dụ 4:

Ví dụ 4. Sự phân giải không gian tên được viết sẵn
public class HardcodedNamespaceResolver implements NamespaceContext {

    /**
     * This method returns the uri for all prefixes needed. Wherever possible
     * it uses XMLConstants.
     * 
     * @param prefix
     * @return uri
     */
    public String getNamespaceURI(String prefix) {
        if (prefix == null) {
            throw new IllegalArgumentException("No prefix provided!");
        } else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
            return "http://univNaSpResolver/book";
        } else if (prefix.equals("books")) {
            return "http://univNaSpResolver/booklist";
        } else if (prefix.equals("fiction")) {
            return "http://univNaSpResolver/fictionbook";
        } else if (prefix.equals("technical")) {
            return "http://univNaSpResolver/sciencebook";
        } else {
            return XMLConstants.NULL_NS_URI;
        }
    }

    public String getPrefix(String namespaceURI) {
        // Not needed in this context.
        return null;
    }

    public Iterator getPrefixes(String namespaceURI) {
        // Not needed in this context.
        return null;
    }

}

Xin lưu ý rằng không gian tên http://univNaSpResolver/sciencebook được gắn với tiền tố technical (không phải science như trước). Bạn sẽ thấy hệ quả trong ví dụ sau (xem Ví dụ 6). Trong Ví dụ 5, đoạn mã sử dụng trình phân giải này sử dụng tiền tố mới.

Ví dụ 5. Ví dụ 1 với sự phân giải không gian tên được viết sẵn trong mã
    private static void example1(Document example)
            throws XPathExpressionException, TransformerException {
        sysout("\n*** First example - namespacelookup hardcoded ***");

        XPath xPath = XPathFactory.newInstance().newXPath();
        xPath.setNamespaceContext(new HardcodedNamespaceResolver());

...
        NodeList result1 = (NodeList) xPath.evaluate(
                "books:booklist/technical:book", example,
                XPathConstants.NODESET);
...
        NodeList result2 = (NodeList) xPath.evaluate(
                "books:booklist/fiction:book", example, XPathConstants.NODESET);
...
        String result = xPath.evaluate("books:booklist/technical:book/:author",
                example);
...
    }

Kết quả như sau.

Ví dụ 6. Kết quả từ ví dụ 1
*** First example - namespacelookup hardcoded ***
Using any namespaces results in a NodeList:
--> books:booklist/technical:book
Number of Nodes: 1
<?xml version="1.0" encoding="UTF-8"?>
  <science:book xmlns:science="http://univNaSpResolver/sciencebook">
    <title xmlns="http://univNaSpResolver/book">Learning XPath</title>
    <author xmlns="http://univNaSpResolver/book">Michael Schmidt</author>
  </science:book>
--> books:booklist/fiction:book
Number of Nodes: 2
<?xml version="1.0" encoding="UTF-8"?>
  <fiction:book xmlns:fiction="http://univNaSpResolver/fictionbook">
    <title xmlns="http://univNaSpResolver/book">Faust I</title>
    <author xmlns="http://univNaSpResolver/book">Johann Wolfgang von Goethe</author>
  </fiction:book>
<?xml version="1.0" encoding="UTF-8"?>
  <fiction:book xmlns:fiction="http://univNaSpResolver/fictionbook">
    <title xmlns="http://univNaSpResolver/book">Faust II</title>
    <author xmlns="http://univNaSpResolver/book">Johann Wolfgang von Goethe</author>
  </fiction:book>
The default namespace works also:
--> books:booklist/technical:book/:author
Michael Schmidt

Như bạn thấy, XPath đã tìm thấy các nút. Điều thuận lợi là bạn có thể thay đổi tên các tiền tố nếu bạn muốn, cái mà tôi đã thực hiện với tiền tố science. Tệp XML chứa tiền tố science, trong khi XPath sử dụng tiền tố khác, technical. Bởi vì các URI là giống nhau, các nốt được tìm thấy bởi XPath. Điều bất tiện là bạn phải duy trì các không gian tên ở nhiều nơi hơn: XML, có lẽ XSD, biểu thức XPath, và ngữ cảnh không gian tên.

Đọc các không gian tên từ tài liệu

Các không gian tên và các tiền tố của chúng được ghi chép trong các tệp XML, do đó bạn có thể sử dụng chúng từ đó. Cách dễ nhất là ủy nhiệm việc tìm kiếm cho tài liệu.

Ví dụ 7. Sự phân giải không gian tên trực tiếp từ tài liệu
public class UniversalNamespaceResolver implements NamespaceContext {
    // the delegate
    private Document sourceDocument;

    /**
     * This constructor stores the source document to search the namespaces in
     * it.
     * 
     * @param document
     *            source document
     */
    public UniversalNamespaceResolver(Document document) {
        sourceDocument = document;
    }

    /**
     * The lookup for the namespace uris is delegated to the stored document.
     * 
     * @param prefix
     *            to search for
     * @return uri
     */
    public String getNamespaceURI(String prefix) {
        if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
            return sourceDocument.lookupNamespaceURI(null);
        } else {
            return sourceDocument.lookupNamespaceURI(prefix);
        }
    }

    /**
     * This method is not needed in this context, but can be implemented in a
     * similar way.
     */
    public String getPrefix(String namespaceURI) {
        return sourceDocument.lookupPrefix(namespaceURI);
    }

    public Iterator getPrefixes(String namespaceURI) {
        // not implemented yet
        return null;
    }

}

Những điều đáng chú ý:

  • Nếu tài liệu bị thay đổi trước khi XPath được dùng, sự thay đổi sẽ được thể hiện trong việc tìm kiếm của không gian tên, bởi vì sự ủy nhiệm được hoàn tất khi cần sử dụng phiên bản hiện tại của tài liệu.
  • Sự tìm kiếm các không gian tên hoặc các tiền tố được hoàn tất trong các nút tiền bối, trong trường hợp của chúng ta nút sourceDocument. Điều này có nghĩa là, với đoạn mã được cung cấp, bạn chỉ lấy các không gian tên được mô tả trong nút gốc. Không gian tên science sẽ được tìm thấy trong ví dụ này.
  • Việc tìm kiếm được gọi khi XPath được ước lượng, vì vậy nó sẽ tiêu tốn thêm một chút thời gian.

Đây là đoạn mã ví dụ:

Ví dụ 8. Ví dụ 2 với sự phân giải không gian tên trực tiếp từ tài liệu
    private static void example2(Document example)
            throws XPathExpressionException, TransformerException {
        sysout("\n*** Second example - namespacelookup delegated to document ***");

        XPath xPath = XPathFactory.newInstance().newXPath();
        xPath.setNamespaceContext(new UniversalNamespaceResolver(example));

        try {
...
            NodeList result1 = (NodeList) xPath.evaluate(
                    "books:booklist/science:book", example,
                    XPathConstants.NODESET);
...
        } catch (XPathExpressionException e) {
...
        }
...
        NodeList result2 = (NodeList) xPath.evaluate(
                "books:booklist/fiction:book", example, XPathConstants.NODESET);
...
        String result = xPath.evaluate(
                "books:booklist/fiction:book[1]/:author", example);
...
    }

Kết quả là:

Ví dụ 9. Kết quả từ ví dụ 2
*** Second example - namespacelookup delegated to document ***
Try to use the science prefix: no result
--> books:booklist/science:book
The resolver only knows namespaces of the first level!
To be precise: Only namespaces above the node, passed in the constructor.
The fiction namespace is such a namespace:
--> books:booklist/fiction:book
Number of Nodes: 2
<?xml version="1.0" encoding="UTF-8"?>
  <fiction:book xmlns:fiction="http://univNaSpResolver/fictionbook">
    <title xmlns="http://univNaSpResolver/book">Faust I</title>
    <author xmlns="http://univNaSpResolver/book">Johann Wolfgang von Goethe</author>
  </fiction:book>
<?xml version="1.0" encoding="UTF-8"?>
  <fiction:book xmlns:fiction="http://univNaSpResolver/fictionbook">
    <title xmlns="http://univNaSpResolver/book">Faust II</title>
    <author xmlns="http://univNaSpResolver/book">Johann Wolfgang von Goethe</author>
  </fiction:book>
The default namespace works also:
--> books:booklist/fiction:book[1]/:author
Johann Wolfgang von Goethe

Như bạn thấy trong kết quả, không gian tên được mô tả trong thành phần book với tiền tố science không được phân giải. Phương thức ước lượng gửi trả lại một XPathExpressionException. Để tránh vấn đề này, bạn có lẽ tách nốt science:book khỏi tài liệu và sử dụng nốt này như là sự ủy nhiệm. Nhưng điều này có nghĩa bạn phải phân tích thêm tài liệu và không hiệu quả cho lắm.

Đọc các không gian tên từ tài liệu và lưu trữ trong vùng đệm

Phiên bản tiếp theo này của NamespaceContext thì tốt hơn. Nó đọc các không gian tên chỉ một lần trong phương thức khởi tạo. Mọi lời gọi cho một không gian tên đều được trả lời từ một vùng đệm. Và kết quả, một sự thay đổi trong tài liệu không ảnh hưởng khi mà danh sách các không gian tên được lưu trữ tạm thời tại thời điểm tạo đối tượng Java.

Ví dụ 10. Lưu trữ sự phân giải không gian tên trong vùng đệm từ tài liệu
public class UniversalNamespaceCache implements NamespaceContext {
    private static final String DEFAULT_NS = "DEFAULT";
    private Map<String, String> prefix2Uri = new HashMap<String, String>();
    private Map<String, String> uri2Prefix = new HashMap<String, String>();

    /**
     * This constructor parses the document and stores all namespaces it can
     * find. If toplevelOnly is true, only namespaces in the root are used.
     * 
     * @param document
     *            source document
     * @param toplevelOnly
     *            restriction of the search to enhance performance
     */
    public UniversalNamespaceCache(Document document, boolean toplevelOnly) {
        examineNode(document.getFirstChild(), toplevelOnly);
        System.out.println("The list of the cached namespaces:");
        for (String key : prefix2Uri.keySet()) {
            System.out
                    .println("prefix " + key + ": uri " + prefix2Uri.get(key));
        }
    }

    /**
     * A single node is read, the namespace attributes are extracted and stored.
     * 
     * @param node
     *            to examine
     * @param attributesOnly,
     *            if true no recursion happens
     */
    private void examineNode(Node node, boolean attributesOnly) {
        NamedNodeMap attributes = node.getAttributes();
        for (int i = 0; i < attributes.getLength(); i++) {
            Node attribute = attributes.item(i);
            storeAttribute((Attr) attribute);
        }

        if (!attributesOnly) {
            NodeList chields = node.getChildNodes();
            for (int i = 0; i < chields.getLength(); i++) {
                Node chield = chields.item(i);
                if (chield.getNodeType() == Node.ELEMENT_NODE)
                    examineNode(chield, false);
            }
        }
    }

    /**
     * This method looks at an attribute and stores it, if it is a namespace
     * attribute.
     * 
     * @param attribute
     *            to examine
     */
    private void storeAttribute(Attr attribute) {
        // examine the attributes in namespace xmlns
        if (attribute.getNamespaceURI() != null
                && attribute.getNamespaceURI().equals(
                        XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
            // Default namespace xmlns="uri goes here"
            if (attribute.getNodeName().equals(XMLConstants.XMLNS_ATTRIBUTE)) {
                putInCache(DEFAULT_NS, attribute.getNodeValue());
            } else {
                // The defined prefixes are stored here
                putInCache(attribute.getLocalName(), attribute.getNodeValue());
            }
        }

    }

    private void putInCache(String prefix, String uri) {
        prefix2Uri.put(prefix, uri);
        uri2Prefix.put(uri, prefix);
    }

    /**
     * This method is called by XPath. It returns the default namespace, if the
     * prefix is null or "".
     * 
     * @param prefix
     *            to search for
     * @return uri
     */
    public String getNamespaceURI(String prefix) {
        if (prefix == null || prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
            return prefix2Uri.get(DEFAULT_NS);
        } else {
            return prefix2Uri.get(prefix);
        }
    }

    /**
     * This method is not needed in this context, but can be implemented in a
     * similar way.
     */
    public String getPrefix(String namespaceURI) {
        return uri2Prefix.get(namespaceURI);
    }

    public Iterator getPrefixes(String namespaceURI) {
        // Not implemented
        return null;
    }

}

Xin lưu ý rằng có kết quả bắt lỗi trong đoạn mã. Các thuộc tính của mỗi nút được kiểm tra và lưu trữ. Các nút con không được kiểm tra, bởi vì biến logic toplevelOnly trong phương thức khởi tạo được đặt là true. Nếu biến logic được đặt là false, sự xem xét các nút con sẽ được bắt đầu sau khi các thuộc tính được lưu trữ. Một điều về đoạn mã cần cân nhắc: Trong DOM, nút đầu tiên sẽ biểu diễn tài liệu như là toàn bộ, vì vậy, để lấy các thành phần book để đọc các không gian tên, bạn phải đi đến nút con một cách chính xác.

Trong trường hợp này, sử dụng NamespaceContext thì đơn giản hơn:

Ví dụ 11. Ví dụ 3 với sự phân giải không gian tên được lưu trữ tạm thời (chỉ cấp độ cao nhất)
    private static void example3(Document example)
            throws XPathExpressionException, TransformerException {
        sysout("\n*** Third example - namespaces of toplevel node cached ***");

        XPath xPath = XPathFactory.newInstance().newXPath();
        xPath.setNamespaceContext(new UniversalNamespaceCache(example, true));

        try {
...
            NodeList result1 = (NodeList) xPath.evaluate(
                    "books:booklist/science:book", example,
                    XPathConstants.NODESET);
...
        } catch (XPathExpressionException e) {
...
        }
...
        NodeList result2 = (NodeList) xPath.evaluate(
                "books:booklist/fiction:book", example, XPathConstants.NODESET);
...
        String result = xPath.evaluate(
                "books:booklist/fiction:book[1]/:author", example);
...
    }

Kết quả như sau:

Ví dụ 12. Kết quả từ ví dụ 3
*** Third example - namespaces of toplevel node cached ***
The list of the cached namespaces:
prefix DEFAULT: uri http://univNaSpResolver/book
prefix fiction: uri http://univNaSpResolver/fictionbook
prefix books: uri http://univNaSpResolver/booklist
Try to use the science prefix:
--> books:booklist/science:book
The cache only knows namespaces of the first level!
The fiction namespace is such a namespace:
--> books:booklist/fiction:book
Number of Nodes: 2
<?xml version="1.0" encoding="UTF-8"?>
  <fiction:book xmlns:fiction="http://univNaSpResolver/fictionbook">
    <title xmlns="http://univNaSpResolver/book">Faust I</title>
    <author xmlns="http://univNaSpResolver/book">Johann Wolfgang von Goethe</author>
  </fiction:book>
<?xml version="1.0" encoding="UTF-8"?>
  <fiction:book xmlns:fiction="http://univNaSpResolver/fictionbook">
    <title xmlns="http://univNaSpResolver/book">Faust II</title>
    <author xmlns="http://univNaSpResolver/book">Johann Wolfgang von Goethe</author>
  </fiction:book>
The default namespace works also:
--> books:booklist/fiction:book[1]/:author
Johann Wolfgang von Goethe

Đoạn mã này chỉ tìm thấy các không gian tên của thành phần gốc. Để cho chính xác: các không gian tên của nút được truyền vào phương thức examineNode bởi phương thức khởi tạo. Điều này làm tăng tốc phương thức khởi tạo bởi vì nó không phải lặp qua toàn bộ tài liệu. Tuy nhiên, như bạn có thể thấy từ kết quả, tiền tố science không thể được phân giải. Biểu thức XPath trả lại một ngoại lệ (XPathExpressionException).

Đọc các không gian tên từ tài liệu và tất cả các thành phần của nó và lưu trong vùng nhớ đệm

Phiên bản này đọc toàn bộ các mô tả không gian tên từ tệp XML. Bây giờ thậm chí XPath trên tiền tố science cũng hoạt động. Một tình huống làm cho phiên bản này trở lên phức tạp: Nếu một tiền tố bị quá tải (được mô tả trong các thành phần lồng nhau trong các URI khác nhau), tiền tố nào tìm thấy cuối cùng sẽ chiến thắng. Trong thực tế, điều này ít khi xảy ra.

Sử dụng NamespaceContext trong ví dụ này cũng giống như trong các ví dụ trước. Biến logic toplevelOnly trong phương thức khởi tạo phải được đặt là false.

Ví dụ 13. Ví dụ 4 với sự phân giải không gian tên được lưu trữ trong vùng đêm (tất cả các cấp độ)
    private static void example4(Document example)
            throws XPathExpressionException, TransformerException {
        sysout("\n*** Fourth example - namespaces all levels cached ***");

        XPath xPath = XPathFactory.newInstance().newXPath();
        xPath.setNamespaceContext(new UniversalNamespaceCache(example, false));
...
        NodeList result1 = (NodeList) xPath.evaluate(
                "books:booklist/science:book", example, XPathConstants.NODESET);
...
        NodeList result2 = (NodeList) xPath.evaluate(
                "books:booklist/fiction:book", example, XPathConstants.NODESET);
...
        String result = xPath.evaluate(
                "books:booklist/fiction:book[1]/:author", example);
...
    }

Kết quả như sau:

Ví dụ 14. Kết quả từ ví dụ 4
*** Fourth example - namespaces all levels cached ***
The list of the cached namespaces:
prefix science: uri http://univNaSpResolver/sciencebook
prefix DEFAULT: uri http://univNaSpResolver/book
prefix fiction: uri http://univNaSpResolver/fictionbook
prefix books: uri http://univNaSpResolver/booklist
Now the use of the science prefix works as well:
--> books:booklist/science:book
Number of Nodes: 1
<?xml version="1.0" encoding="UTF-8"?>
  <science:book xmlns:science="http://univNaSpResolver/sciencebook">
    <title xmlns="http://univNaSpResolver/book">Learning XPath</title>
    <author xmlns="http://univNaSpResolver/book">Michael Schmidt</author>
  </science:book>
The fiction namespace is resolved:
--> books:booklist/fiction:book
Number of Nodes: 2
<?xml version="1.0" encoding="UTF-8"?>
  <fiction:book xmlns:fiction="http://univNaSpResolver/fictionbook">
    <title xmlns="http://univNaSpResolver/book">Faust I</title>
    <author xmlns="http://univNaSpResolver/book">Johann Wolfgang von Goethe</author>
  </fiction:book>
<?xml version="1.0" encoding="UTF-8"?>
  <fiction:book xmlns:fiction="http://univNaSpResolver/fictionbook">
    <title xmlns="http://univNaSpResolver/book">Faust II</title>
    <author xmlns="http://univNaSpResolver/book">Johann Wolfgang von Goethe</author>
  </fiction:book>
The default namespace works also:
--> books:booklist/fiction:book[1]/:author
Johann Wolfgang von Goethe

Kết luận

Bạn có thể chọn từ một vài ý tưởng cho việc cài đặt sự phân giải không gian tên mà có lẽ là tốt hơn việc viết sẵn chúng trong mã:

  • Nếu ví dụ của bạn là nhỏ và tất cả các không gian tên được định vị ở thành phần trên cùng, hãy ủy nhiệm việc tìm kiếm cho tài liệu.
  • Nếu bạn có tệp XML lớn hơn với nhiều cấp độ lồng nhau và nhiều ước lượng XPath, có lẽ cách tốt hơn hết là lưu trữ tạm thời danh sách các không gian tên.
  • Nhưng nếu bạn không phải điều khiển qua các tệp XML, và ai đó có thể gửi cho bạn bất cứ tiền tố nào họ muốn, có lẽ cách tốt hơn hết là độc lập khỏi các lựa chọn của họ. Bạn có thể viết mã sự phân giải không gian tên của chính bạn như trong Ví dụ 1 (HardcodedNamespaceResolver), và sử dụng chúng trong các biểu thức XPath của bạn.

Trong các trường hợp khác, NamespaceContext được phân giải từ tệp XML có thể làm cho mã của bạn tổng quát hơn và nhỏ hơn.


Tải về

Mô tảTênKích thước
Source code for the examplessourceCode.zip7KB

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

Thảo luận

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Nguồn mở, Công nghệ Java
ArticleID=413535
ArticleTitle=Sử dụng đối tượng NamespaceContext của ngôn ngữ Java với XPath
publish-date=07172009