(二) 解析XML文档(parse xml)

Java库提供了两种XML解析器
(1)文档对象模型(Document Object Model, DOM)解析器,树形解析器(tree parser),将读入的XML转换成树形结构。
(2)用于XML的简单API(Simple API for XML,SAX)解析器,流机制解析器(streaming parser),在读入XML文档时生成相应的事件。

1.DOM解析器
当处理大文档时,树结构将会消耗大量内存,或只针对于某些元素时,应选用流机制解析器(SAX)。

 

在开始解析之前,可以设置Crimson(默认,sun)或Xerces(IBM,classpath中要有xerces.jar(其中包含了sax dom jaxp )和 xercesImpl.jar)

System.setProperty("javax.xml.parsers.DocumentBuilderFactory","org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");

 

(1)读入一个XML文档,需要一个DocumentBuilder对象,可以从DocumentBuilderFactory中得到这个对象。

    javax.xml.parsers.DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    javax.xml.parsers.DocumentBuilder builder = factory.newDocumentBuilder();

 

(2)读入文档 org.w3c.dom.Document

 

org.w3c.dom.Document doc = builder.parse(file);

 

    或者用URL

org.w3c.dom.Document doc = builder.parse(url);

 

   或使用一个任意的输入流

org.w3c.dom.Document doc = builder.parse(inputStream);

 

注意:如果使用输入流,那么对于通过相对于文档的位置关系来引用的文件,解析器将无法定位,比如在同一个目录中的DTD。但是可以通过安装一个 实体分解器(entity resolver) 来解决这个问题。

(3)Document对象是XML文档的树型结构在内存中的表现,它由实现Node接口及其多个子接口的类的对象构成。可以通过调用getDocumentElement方法来分析文档的内容,它将返回root element(根元素)。

org.w3c.dom.Element root = doc.getDocumentElement();

 

(4)要得到该元素的下一个节点(子元素、文本、注释或其他节点),使用getChildNodes方法。这个方法返回一个类型为NodeList的集合。NodeList集合
NodeList在标准Java集合类创建之前就建立了,与标准Java集合类访问协议不同。item方法得到指定索引号的项,getLength方法返回项的总数。
e.g.枚举所有子元素

    org.w3c.dom.NodeList childNodes = roog.getChildNodes();
    for(int i=0;i<childNodes.getLength();i++){
        org.w3c.dom.Node childNode = childNodes.item();
    }

 

注意:子元素会比期望值高

 

    <font>
        <name>Helvetica</name>
        <size>36</size>
    </font>

 

font会有5个子节点,而不是期望中的2个。<font>和<name>之间的空格,name元素,</name>和<size>之间的空白字符,size元素,</size>和</font>之间的空白字符。
如果只希望得到子元素,需要忽略空白字符

 

    for(int i=0;i<childNodes.getLength();i++){
        Node child = childNodes.item(i);
        if(child instanceof Element){
            Element childElement = (Element)child;
        }
    }

 


如果有DTD,解析器就可以知道哪些元素没有文本节点的子元素,而且会帮助禁止掉空白字符。
(5)分析子元素所包含的文本字符串org.w3c.dom.Text,比如上例中的name和size。这些文本字符串本身都包含在Text类型的子节点中。因为Text类型是唯一的子元素,可以用getFirstChild方法,而不用遍历一个NodeList。然后用getData方法检索存储在Text节点中的字符串。

 

    NodeList childNodes = root.getChildNodes();
    for(int i=0;i<childNodes.getLength();i++){
        Node child = childNodes.item(i);
        if(child instanceof Element){
            Element childElement = (Element)child;
            Text textNode = (Text)childElement.getFirstChild();
            String text = textNode.getData().trim();
            if("name".equals(childElement.getTagName())){
                name = text;
            }else if("size".equals(childElement.getTagName())){
                size = text;
            }           
        }
    }

 

对getData方法的返回值调用trim方法。因为起始和结束标签可能不在同一行上,导致空白字符

也可以用getLastChild方法得到最后一项子元素

 

    Document doc = builder.parse(xml);
    Element root = doc.getDocumentElement();
   
    for(Node childNode = root.getFirstChild();childNode !=null;childNode  = childNode.getNextSibling()){
        if(childNode instanceof Element){
            Text textNode = (Text)childNode.getLastChild();
            String text = textNode.getData();
        }
    }

 


(6)枚举节点的属性,通过调用Node的getAttributes方法,如果节点是Element返回NamedNodeMap,否则返回null。

 

    if(childNode instanceof Element){
        NamedNodeMap attributes = childNode.getAttributes();
        for(int i=0;i<attributes.getLength();i++){
            Node attribute = attributes.item(i);
            String name = attribute.getNodeName();
            String value = attribute.getNodeValue();
            System.out.println();
        }
    }

 

或者根据已知的属性名,得到通过Element的getAttribute(String name) 来获得属性,如果没有指定值或默认值,则返回空字符串。

 

    if(childNode instanceof Element){
        Element childElement = (Element)childNode;
        String value = childElement.getAttribute("unit");
        System.out.println(value);
    }

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值