java与xml

java解析xml文档――Dom方式,Sax方式。

其实对于java解析xml文档的方式,感到有点奇怪啊,默认情况下,主要是在“节点”方面。为什么呢?就是因为java解析的太细了。

如下片段

<book>
    <title>java</title>
    <writer>tom</writer>
    <publisher>武汉大学出版社</publisher>
    <content xxx="xxxaa">
        <title>简介</title>
        <detail>java介绍</detail>
    </content>
</book>

不管是那种方式进行解析都会把标签之间的回车,空格算作#text类型

如:在dom方式中book的子节点数有:9个(title,writer,publisher,content,以及从book开始到/book结束,和它子元素之间的五个空字符(回车等))。也就是说:除非<book>……</book>他们直接不有任何的空字符的时候,book的子节点数九只有“四个”。

因此,我人java对xml文档的解析太过于细微了,毕竟,我们需要的不是标签之间无关紧要的空字符(空字符只是为了美观,格式等)。


在xml中最关键的就是Node(文档节点,元素节点,文本节点……),即所有的都是节点。


接下来谈谈这两种方式如何解析xml:

1、Dom方式――主要获取Document对象。parse解析的时候即可以是输入流,也可以是文件路径或文件对象。

public void traverse(Node root){
    NodeList list = root.getChildNodes();
    int len = list.getLength();
    System.out.println(len);
    for(int i = 0; i < len; i++) {
    Node n = list.item(i);
    if(n.hasChildNodes()){
            traverse(n);
    }
    String s = "Name:" + n.getNodeName();
    s += "\tType:" + n.getNodeType();
    s += "\tValue:" + n.getNodeValue();
    s += "\tbaseURI" + n.getBaseURI();
    System.out.println(s);
    }
}
public void dom(String path){
    DocumentBuilderFactory fac = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = null;
    try{
    builder =  fac.newDocumentBuilder();
    Document doc = builder.parse(path);
    Element root = doc.getDocumentElement();
    traverse(root);
    } catch (Exception e) {
    e.printStackTrace();
    }
}


2、sax ―― 通过DefaultHandler对象获取xml文档节点的内容

public String sax(){
        SAXParserFactory fac = SAXParserFactory.newInstance();
        String r = "";
        SAXParser sax = null;
        try{
            sax = fac.newSAXParser();
            MyHandle handle = new MyHandle();
            sax.parse(path, handle);
            //XMLReader rr = sax.getXMLReader();
            //rr.setContentHandler(handle);
            //XMLReader reader = sax.getXMLReader();//XMLReaderFactory.createXMLReader();
            r = handle.getResult();
        }catch(Exception e){
            e.printStackTrace();
        }
        return r;
    }
                                                                                                                                                                                       
    class MyHandle extends DefaultHandler{
        StringBuilder sb = new StringBuilder(1000);
                                                                                                                                                                                           
        /**
         * 获取元素的内容如:<sex>boy</sex> data从start开始len长度存放的是boy。
         * <sex>
         * boy
         * </sex>
         * data中从start开始len长度是、\n boy \n
         * 如果将所有的内容拼接在一起的话,内容就是除去<>包含的剩下的字符
         * <sex>man</sex>    <name>LC</name>在sex和那么之间的空格都会只出发characters方法的执行
         */
        @Override
        public void characters(char[] data, int start, int len)
                throws SAXException {
            sb.append(data, start, len);
            System.out.println(start + ":" + len);
            System.out.print(new String(data));
        }
        @Override
        public void endDocument() throws SAXException {
            System.out.println("解析结束");
        }
        @Override
        public void endElement(String s1, String s2, String s3)
                throws SAXException {
            System.out.println("s1:" + s1 + "\ts2:" + s2 + "\ts3:" + s3);
            System.out.println("元素解析完成");
        }
        @Override
        public void startDocument() throws SAXException {
            System.out.println("开始解析文档");
        }
        @Override
        public void startElement(String s1, String s2, String s3,
                Attributes att) throws SAXException {
            System.out.println("开始解析元素");
            System.out.println("s1:" + s1 + "\ts2:" + s2 + "\ts3:" + s3);
            System.out.println(att.getLength() + att.getType(0) + att.getQName(0) + att.getValue(0));
        }
                                                                                                                                                                                           
        public String getResult(){
            return sb.toString();
        }
    }
                                                                                                                                                                                      


查看DefaultHandler的源码,你发现此类的绝大多数方法都是空的// no op

因为这些方法是在解析文档时,所触发事件而引起的回调。

(1)解析文档的时候

会先调用startDocument,最后调用endDocument方法。

从名字可以知道,是开始解析文档时候和文档解析结束的时候调用的方法。

(2)在解析一个节点元素的时候(如:writer)

那么会依次调用startElement,characters,endElement方法

startElement方法接收元素开始的通知。参数依次为uri,localName,qName,atts

前三个都是String类型的,就名字而言,可以猜出他们代表的是什么意思了

最后一个是Attributes类型的,即:属性列表(查看实现类源码可知,数据是用String[]存储的)。根据Attributes中的方法可以访问各个属性名字,值,类型等等。

characters方法接收字符的通知。参数依次为ch,start,length

ch是char[]类型的,后两个为int类型。此参数名字可以猜到ch是存文档中字符的(出去声明等)。在writer中那么从start开始length长度的字符串为:tom

endElement方法接收元素结束的通知。参数依次为uri,localName,qName,这个三个内容和startElement中的内容是一样的,只是在ch中的位置索引不同罢了。

(3)在DefaultHandler中还有其他的方法,只是以上的方法是最常用的。只是在DefaultHandler中没有对方法进行逻辑处理,也没有什么进行数据存储,故,在正真应用的时候,应该重写这些方法进行解析操作,可以提供容器进行数据分离存储。


3、文档其他设置――文档验证,schema设置,解析器等

这些主要是在创建工厂(DocumentBuilderFactory和SAXParserFactory中)中进行设置。











你可能感兴趣的:(java,dom,sax,node,解析xml)