java jdk 自带 DOM 解析xml 笔记

JDK 自带dom 解析xml时 做的一些总结。

前言

xml的读取

先看一下一个简单的xml 格式

<root>
    <a id='1' cc='2' >
        <b>ss</b>
    </a>
    <c>s2</c>
    <d>
        <![CDATA[<e><f>f1</f></e>]]>
    </d>
</root>

可以看出这个是一个常见的xml格式了。
针对dom解析来说。
每一个出现的节点都是一个元素就是Node 对象
举例 root 节点是一个Node对象。
其中a b c d也是一个Node对象 。
而且里面的值也是一个node对象 ss ,s2, cdata中的内容,
只是其中在Node对象中。他们的类型不一样。
要先了解一下Node对象中的元素类型了 所谓的element type
看下Node源码:摘抄出来坐下简单的注释

NodeType 类型介绍

 // NodeType
    /**
     * 元素节点 可以被get 到子元素
     */
    public static final short ELEMENT_NODE              = 1;
    /**
     * 属性 从node中 get attribute 获取 获取一个 node集合在迭代获取此类型
     */
    public static final short ATTRIBUTE_NODE            = 2;
    /**
     *文本内容通过get value获取。 类型1 获取value 为null 必须获取内容才行
     */
    public static final short TEXT_NODE                 = 3;
    /**
     * CDATA 类型数据
     */
    public static final short CDATA_SECTION_NODE        = 4;
    /**
     * The node is an <code>EntityReference</code>.
     */
    public static final short ENTITY_REFERENCE_NODE     = 5;
    /**
     * The node is an <code>Entity</code>.
     */
    public static final short ENTITY_NODE               = 6;
    /**
     * The node is a <code>ProcessingInstruction</code>.
     */
    public static final short PROCESSING_INSTRUCTION_NODE = 7;
    /**
     * 注释类型
     */
    public static final short COMMENT_NODE              = 8;
    /**
     * 
     */
    public static final short DOCUMENT_NODE             = 9;
    /**
     * document 描述类型节点
     */
    public static final short DOCUMENT_TYPE_NODE        = 10;
    /**
     * The node is a <code>DocumentFragment</code>.
     */
    public static final short DOCUMENT_FRAGMENT_NODE    = 11;
    /**
     * The node is a <code>Notation</code>.
     */
    public static final short NOTATION_NODE             = 12;
ELEMENT_NODE 类型

上代码过程吧 ,一步一步了解

public static void main(String[] args) {
		// 1.创建DocumentBuilderFactory对象
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		// 2.创建DocumentBuilder对象
		try {
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document d = builder.parse(new ByteArrayInputStream(xml2.getBytes()));
			renshiNodeType(d.getChildNodes());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public static void renshiNodeType(NodeList list) {
		for(int i=0;i<list.getLength();i++)
		{
			Node _n = list.item(i);
			log.info("{} {} {}",_n.getNodeType(),_n.getNodeName(),_n.getNodeValue());
		}
	}
	static String xml2 = "<root><a>sss</a></root>";

输出结果

[main] INFO org.cmcc.ecip.examples.xml.Dom - 1 root null

说明这个root 对象是一个Node对象但是取不到他的值。

TEXT_NODE

改造一下在循环,修改方法renshiNodeType

public static void renshiNodeType(NodeList list) {
		for(int i=0;i<list.getLength();i++)
		{
			Node _n = list.item(i);
			log.info("{} {} {}",_n.getNodeType(),_n.getNodeName(),_n.getNodeValue());
			
			if(_n.getNodeType() == 1) {
				renshiNodeType(_n.getChildNodes());
			}
		}
	}

运行后得到了结果

[main] INFO org.cmcc.ecip.examples.xml.Dom - 1 root null
[main] INFO org.cmcc.ecip.examples.xml.Dom - 1 a null
[main] INFO org.cmcc.ecip.examples.xml.Dom - 3 #text sss

可以看到了这个最简单的xml 对象中sss值作为 type为3的结果输出了出来

CDATA_SECTION_NODE

我们用这个方法输出一下开始定义的xml格式结果

[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 1 root null
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 1 a null
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 1 b null
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 3 #text ss
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 1 c null
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 3 #text s2
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 1 d null
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 4 #cdata-section <e><f>f1</f></e>

可以看出来 cdata 被搞出来了 是类型4

ATTRIBUTE_NODE

但是对于

<a id='1' cc='2' >

中的id 和cc 没有搞出来。
这是需要修改一下方法增加一个新的循环内容 针对attribute的

public static void renshiNodeType(NodeList list) {
		for (int i = 0; i < list.getLength(); i++) {
			Node _n = list.item(i);
			log.info("node >> {} {} {}", _n.getNodeType(), _n.getNodeName(), _n.getNodeValue());
			NamedNodeMap map = _n.getAttributes();
			for (int j = 0; map != null && j < map.getLength(); j++) {
				Node an = map.item(j);
				log.info("attr >> {} {} {}", an.getNodeType(), an.getNodeName(), an.getNodeValue());
			}
			if (_n.getNodeType() == 1) {
				renshiNodeType(_n.getChildNodes());
			}
		}
	}

在运行以后,看结果

[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 1 root null
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 1 a null
[main] INFO org.cmcc.ecip.examples.xml.Dom - attr >> 2 cc 2
[main] INFO org.cmcc.ecip.examples.xml.Dom - attr >> 2 id 1
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 1 b null
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 3 #text ss
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 1 c null
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 3 #text s2
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 1 d null
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 4 #cdata-section <e><f>f1</f></e>

id 和cc 的type被搞出来了。是2

其实到这里非常常用的类型就已经搞出来了。

COMMENT_NODE & DOCUMENT_TYPE_NODE

但是还有其他几种类型不知道怎么搞。简单改了一下xml看看一下xml就知道了。

<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!-- this is comment -->" 
<!DOCTYPE root[<!ELEMENT users (a+)>]>
<root><a>sss</a></root>

对这个 xml运行一下结果

[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 8 #comment  this is comment  null
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 10 root null null
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 1 root null null
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 1 a null null
[main] INFO org.cmcc.ecip.examples.xml.Dom - node >> 3 #text sss null

显而易见了。

总结一下

关于读取xml
对于几种常用类型的解析 需要用到的方法有

getNodeType   获取类型
getNodeName  获取节点名称 当为Text  类型为 name 就是#text 对于 comment 类型也是这样
getNodeValue 只有text类型获取有返回值。要是其他类型返回null

xml的创建于生成

看一个简单的例子

public static void main(String a[]) throws Exception {
		
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document document = builder.newDocument();
		// 创建各个节点并相互进行append为树形结果。 
		//对比文章上半部分看好创建的方法名称与 实际类型
		Element rootNode = document.createElement("root");
		Element aa1 = document.createElement("aa1");
		Attr a3 = document.createAttribute("a3");
		a3.setNodeValue("a31");
		a3.setTextContent("a32");
		a3.setValue("a33");
		Attr a4 = document.createAttributeNS("http://namespce.test2","cc:a4");
		a4.setNodeValue("a41");
		a4.setTextContent("a42");
		a4.setValue("a43");
		aa1.setAttributeNode(a3);
		aa1.setAttributeNode(a4);
		Element a2 = document.createElementNS("http://namespce.test1", "dd:a2");
		Text a2_v=document.createTextNode("a2 value");
		a2.appendChild(a2_v);
		aa1.appendChild(a2);
		rootNode.appendChild(aa1);
		CDATASection a5 =document.createCDATASection("<s>sss</s>");
		EntityReference a6=	document.createEntityReference("sdddd");
		Text a7=document.createTextNode("test hello..");
		Element aa2 = document.createElement("aa2");
		aa2.appendChild(a5);
		aa2.appendChild(a6);
		aa2.appendChild(a7);
		rootNode.appendChild(aa2);
		document.appendChild(rootNode);
		// 创建完成了进行输出
		TransformerFactory tff = TransformerFactory.newInstance();
		//这个是显示格式化用的
		Transformer tf = tff.newTransformer();
		tf.setOutputProperty(OutputKeys.INDENT, "yes");
		tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
		//输出。这里用到控制台了。所以用了system.out
		tf.transform(new DOMSource(document), new StreamResult(System.out));
	}

执行结果

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
  <aa1 a3="a33" xmlns:cc="http://namespce.test2" cc:a4="a43">
    <dd:a2 xmlns:dd="http://namespce.test1">a2 value</dd:a2>
  </aa1>
  <aa2><![CDATA[<s>sss</s>]]>test hello..</aa2>
</root>

总结一下

对于dom创建xml 需要先构建一个 document 对象。再通过document创建需要的各种元素。创建完成后需要进行树形的构造。一个节点挂载到另外一个节点中去。就是appendChild。
关于dom创建时候关于头部声明 standalone 需要去掉的话 加上如下代码

	// 去掉头部声明 standalone="no"
		document.setXmlStandalone(true);
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值