java中如何对多节点的xml文档进行dom解析

java中如何对多节点的xml文档进行dom解析

问题描述:

如下XML文档:首先我知道如何解析如hd节点下的code,desc,pid的属性值,但如果是bd下的节点data(因为服务器返回给我的data节点不是每次都有的)而且对于data节点下的嵌套节点usd节点下的属性怎么获取,并且怎么判断是否有data节点,望各位熟悉的指点下,对NodeList,Node和XML的格式做些介绍解释,等我明白了,我会整理一份教程心得,并签上XX指导,谢谢,本人是做J2me的,对XML的解析不是太熟悉,API看的不太明白,我用的是javax.xml.parsers和org.w3c.dom包

<?xml version="1.0" encoding="UTF-8"?>
<res>
    <hd><!--通用请求结果说明信息-->
        <code>0|1</code><!--请求结果:0、失败,1、成功-->
        <desc>sucess|其它描述内容</desc>
        <pid>11</pid><!--协议ID-->
    </hd>
    <bd>
    <data><!--版本数据处理(非必有)-->
        <usd><!--新域名处理-->
        <id>0</id><!--序号-->
        <dn>http://wap.133.cn</dn><!--新域名-->
        <usd>
        <udv><!--更新客户端数据版本号-->
        <id>1</id><!--序号-->
        <dn>2.0</dn><!--新客户端数据版本号-->
        <udv>
        <uud><!--用户ID更新-->
        <id>2</id><!--序号-->
        <uid>11001</uid><!--新用户id-->
        <uud>
        <uct><!--城市数据更新-->
        <id>3</id><!--序号-->
        <to>0|1</to><!--0.替换,1.增加-->
        <ls><!--城市列表-->
            <it>
                <n>北京<n/><!--城市中文名-->
                <p>BEIJING<p/><!--城市拼音编码-->
                <j>BJ<j/><!--城市简拼编码-->
                <s>PEK<s/><!--三字码-->
            </it>
            ......
        </ls>
        <uct>
        <utm><!--航班时段更新-->
        <id>4</id><!--序号-->
        <to>0|1</to><!--0.替换,1.增加-->
        <ls><!--航班时段列表-->
            <it>
                <i>4<i/><!--数据编号-->
                <n>不限<n/><!--名称-->
            </it>
            ......
        </ls>
        <utm>
        <uac><!--航空公司更新-->
        <id>5</id><!--序号-->
        <to>0|1</to><!--0.替换,1.增加-->
        <ls><!--航空公司列表-->
            <it>
                <i>CA<i/><!--航空公司简码-->
                <n>中国国际航空公司<n/><!--航空公司名称-->
            </it>
            ......
        </ls>
        <uac>
        <ucb><!--舱位信息更新-->
        <id>6</id><!--序号-->
        <to>0|1</to><!--0.替换,1.增加-->
        <ls><!--舱位列表-->
            <it>
                <i>0<i/><!--舱位ID-->
                <n>经济舱<n/><!--舱位名称-->
            </it>
            ......
        </ls>
        <ucb>
        <ucd><!--证件信息更新-->
        <id>7</id><!--序号-->
        <to>0|1</to><!--0.替换,1.增加-->
        <ls><!--证件信息列表-->
            <it>
                <i>0<i/><!--证件信息简码-->
                <n>身份证<n/><!--证件信息名称-->
            </it>
            ......
        </ls>
        <ucd>
        <ucv><!--客户端更新-->
        <id>8</id><!--序号-->
        <cvt>版本更新</cvt><!--标题-->
        <cvc>系统检测到当前有新版本,是否立即更新?</cvc><!--内容-->
        <url>http://wap.133.cn/Fly.jar</url><!--下载地址-->
        <ucv>
        <uoc><!--订票电话更新-->
        <id>9</id><!--序号-->
        <to>0|1</to><!--0.替换,1.增加-->
        <ls><!--订票电话列表-->
            <it>
                <i>0<i/><!--订票电话ID-->
                <tel>4008158888<tel/><!--订票电话-->
                <n>中航信<n/><!--订票代现名称-->
            </it>
            ......
        </ls>
        <uoc>
    </data>
    <fly><!--航班信息-->
        <code>0|1</code><!--查询结果0.失败,1.成功-->
        <num>47</num><!--航班总数-->
        <pub>PEK,SHA,2009,05,27</pub><!--公共参数:详情的para1值-->
        <fm>2,10,1,0,0,0,2,0,0,0,3,0,0,0,4,0,01,01,250,01,01,01,5,0,0,0,6,0,0,0,7,0,1,1,250,1,1,1,0,8,0,0,0,9,0,0,0</fm><!--配色方案-->
        <!--配色方案说明(对应里面的内容):方案数,要显示的字段数(包括换行控制),要显示的字段号(对应下面标签<it>里面数据的id号),文字大小控制(备用)、颜色方案1,颜色方案2(颜色方案非零用三位表示,比方4后面的01,01,250,为颜色方案1)......除掉这些外,如果遇到数字0便视为换行控制(因为0号ID不可能作为显示字段,被用作返回参数了),实际返回中“,”号将会被空格(\t)取代。-->
 
        <ls>
            <it>
                <d id="0">CA984,321,0,0720,0930,PEK,PVG,Q,6.7,770,4</d>
                <!--详细数据:详情的para2值-->
                <d id="1">国航</d><!--航空公司简称-->
                <d id="2">CA984</d><!--航班号-->
                <d id="3">09:30</d><!--起飞时间-->
                <d id="4">770</d><!--机票价格-->
                <d id="5">6.7折</d><!--折扣-->
                <d id="6">北京首都国际机场</d><!--起飞机场名-->
                <d id="7">上海浦东机场</d><!--到达机场名-->
                <d id="8">321</d><!--机型-->
                <d id="9">9</d><!--票数:0~9或9张以上-->
                <f>1</f><!--选用哪套格式化方案-->
            </it>
            ......
        </ls>
    </fly>
    <bd>
</res>

 


问题补充:
我把XML附件加上来
大家要注意<data>节点下的,这个文件有些没有,因为只有要更新了才会有返回相应节点.望有兴趣的朋友赐教,大家以后一起讨论学习

[code="java"]
import java.io.FileInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class TestXml {

public void parserDATA(org.w3c.dom.Node node){
    if (node.getNodeType() == org.w3c.dom.Node.TEXT_NODE) {
        return;
    }
    if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
        Element element = (Element) node;
        if(element.getTagName().equals("DATA")){
            System.out.println(element.TEXT_NODE);
        }
        org.w3c.dom.NodeList list = element.getChildNodes();
        for (int i = 0; i < list.getLength(); i++) {
            parserDATA(list.item(i));
        }
    } 
}

/**
 * @param html
 * @return 返回w3c dom 对象
 */
public Document getDocument(String html) throws Exception{
    //生成html parser   
    org.cyberneko.html.parsers.DOMParser parser = new org.cyberneko.html.parsers.DOMParser();   
    //设置网页的默认编码   
    parser.setFeature("http://xml.org/sax/features/validation", true);
    parser.setFeature("http://xml.org/sax/features/namespaces", false);
    parser.parse(html);
    return parser.getDocument();
}

/**
 * 
*/
public Document getDocument(){
    try {
        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        FileInputStream in = new FileInputStream("Test1.xml");
        Document document = db.parse(in);
        return document;
    }catch(Exception e){
        e.printStackTrace();
        return null;
    }
}
/**
 * 判断是否有data节点
 */
public boolean isData(){
    return getDocument().getElementsByTagName("data").getLength()>0?true:false;
}

/**
 * 获取一个节点下面某个子节点和子节点属性
 */
public void getChildNodeOrAttr(NodeList list,String NodeName,String NodeAttr){
    for(int i=0;i<list.getLength();i++){
        Node node = list.item(i);
        Element element = (Element)node;
        NodeList listChild = list.item(i).getChildNodes();
        for(int j=0;j<listChild.getLength();j++){
            Node nodeChilde = listChild.item(j);
            if (nodeChilde.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
                Element elementChilde = (Element)nodeChilde;
                if(elementChilde.getTagName().equals(NodeName)){
                    System.out.println("父节点:"+element.getTagName()+" 已经获取到子节点:"+NodeName+" 子节点属性值:"+elementChilde.getAttribute(NodeAttr));                  
                }
            }
        }
        System.out.println("一个父节点完毕");
    }
}

public static void main(String[] args) {
    // TODO Auto-generated method stub
    TestXml testxml = new TestXml();
    NodeList nl = testxml.getDocument().getElementsByTagName("it");
    testxml.getChildNodeOrAttr(nl,"d","id");
}

}

[/code]
是否完成你的需求了?

可以遍历节点,挨个获取每个节点。
例子如下:
[code="java"]
public void parserNode(org.w3c.dom.Node node){
if (node.getNodeType() == org.w3c.dom.Node.TEXT_NODE) {
return;
}
if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
Element element = (Element) node;

        org.w3c.dom.NodeList list = element.getChildNodes();
        for (int i = 0; i < list.getLength(); i++) {
            parserNode(list.item(i));
        }
    }     
}

[/code]

我认真看了一下 但是发现很多xml标签不是一对 都只有头而已

如果样板本身就是这种错误语法 那么解析起来就是地狱

如果只是javaeye粘贴xml出现的问题...建议你xml样本以附件的形式上传

本身想帮你一把 可以我惯用dom4j 和你用的包不同 用法也有些不同....