1. 程式人生 > >Dom4J配合XPath解析schema約束的xml配置文件問題

Dom4J配合XPath解析schema約束的xml配置文件問題

ali sel tex publish string exceptio xml文件 exc hashmap

如果一個xml文件沒有引入約束,或者引入的是DTD約束時,那麽使用dom4j和xpath是可以正常解析的,不引入約束的情況本文不再展示。

引入DTD約束的情況

  • mybook.dtd:
<?xml version="1.0" encoding="UTF-8" ?>
<!ELEMENT books (book+)>
<!ELEMENT book (name|author|price)+>
<!ELEMENT name (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT price (#PCDATA)>
<!ATTLIST book id ID #REQUIRED publish CDATA #IMPLIED>
  • book.xml:
<?xml version="1.0" encoding="UTF-8 ?>
<!DOCTYPE books SYSTEM "mybook.dtd">
<books>
    <book id="_001">
        <name>西遊記</name>
    </book>
    <book id="_002">
        <name>三國演義</name>
    </book>
    <book id="_003">
        <name>水滸傳</name>
    </book>
    <book id="_004">
        <name>紅樓夢</name>
    </book>
</books>

測試類:

public class DemoBook {
    public static void main(String[] args) throws DocumentException {
        SAXReader reader = new SAXReader();
        Document document = reader.read(DemoBook.class.getResourceAsStream("book.xml"));
        List<Node> nodes = document.selectNodes("//name");
        for (Node node : nodes) {
            Element element = (Element) node;
            System.out.print(element.getText()+" ");
        }
    }
}

//輸出結果:西遊記 三國演義 水滸傳 紅樓夢 

可見,引入了DTD約束的xml是可以通過dom4j和xpath表達式正常解析的.而引入Schema約束的時候呢?

引入Schema約束的情況

  • mybook.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://www.mytest.com/book"
    elementFormDefault="qualified">
    <element name="books">
        <complexType>
            <sequence maxOccurs="unbounded">
                <element name="book">
                    <complexType>
                        <choice maxOccurs="unbounded">
                            <element name="name" type="string"></element>
                            <element name="author" type="string"></element>
                        </choice>
                    </complexType>
                </element>
            </sequence>
        </complexType>
    </element>
</schema>
  • book.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<books
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://www.mytest.com/book"
        xsi:schemaLocation="http://www.mytest.com/book /mybook.xsd"
>
    <book>
        <name>西遊記</name>
    </book>
    <book>
        <name>三國演義</name>
    </book>
    <book>
        <name>水滸傳</name>
    </book>
    <book>
        <name>紅樓夢</name>
    </book>
</books>

測試類:

public class DemoBook {
    public static void main(String[] args) throws DocumentException {
        SAXReader reader = new SAXReader();
        Document document = reader.read(DemoBook.class.getResourceAsStream("book.xml"));
        List<Node> nodes = document.selectNodes("//name");
        for (Node node : nodes) {
            Element element = (Element) node;
            System.out.println(element.getText());
        }
    }
}

結果為:

技術分享圖片

我們會發現,同樣的代碼,運行在引入了Schema約束的xml文件上雖然正常運行了,但是並沒有達到我們想要的結果,document對象獲取到的nodes集合是個空集合[]

產生問題的原因

當XPath表達式中沒有前綴時,查詢的元素命名空間也應該是默認值,否則是查詢不到結果的。引入了Schema約束的xml文件使用了命名空間,此時查詢元素的命名空間不再是默認值了,所以此時的結果是個空集合。

解決方案:

此時如果想要正確的解析結果,必須設置命名空間後再對文檔進行解析。

修改後的測試類:

public class DemoBook {
    public static void main(String[] args) throws DocumentException {
        SAXReader reader = new SAXReader();
        //聲明一個map集合保存命名空間
        Map<String,String > map = new HashMap<>();
        //給命名空間取別名
        map.put("myNameSpace","http://www.mytest.com/book");
        //設置命名空間
        reader.getDocumentFactory().setXPathNamespaceURIs(map);
        //讀取文檔
        Document document = reader.read(Demo1.class.getResourceAsStream("book.xml"));
        List<Node> nodes = document.selectNodes("//myNameSpace:name");
        for (Node node : nodes) {
            Element element = (Element)node;
            System.out.println(element.getText());
        }
    }
}

運行結果:
技術分享圖片

Perfect~

Dom4J配合XPath解析schema約束的xml配置文件問題