• 大话XML解析


    之前我写过一篇关于xml解析的文章:http://blog.csdn.net/sdksdk0/article/details/50749326。今天这篇文章主要是进一步加深对xml基础的理解了使用,毕竟基础是很重要的嘛!写的应该会更注重细节的内容。主要内容有xml语法、DOM解析、SAX解析、Xpath,schema约束。


    一、xml语法

    标签

    1. 有开始标签和结束标签
    2. xml标签名称区分大小写
    3. xml标签一定要正确配对
    4. 中间不能使用空格
    5. 不能以数字开头,可以以下划线或字母开头
    6. 在一个xml文档中,有且仅有一个根标签

    属性

    1. 属性值一定要以引号包含,也不能单双引号混用 name="erim"
    2. 一个标签内可以多个属性,但是属性名不能重复,例如不能有两个 id="1" id="2"

    注释

    <!--xml的注释  -->

    文档申明

    如果在ide中开发,保存xml文件时会自动按照文档申明的encoding来保存。

     <?xml version="1.0" encoding="utf-8"?>
    

    转义字符

    <   &lt;
    >   &gt;
    "   &quot;
    &   &amp;
    空格 &nbsp;
    
    写法:&lt;p&gt;段落&lt;/p&gt;
    

    CDATA块

    作用,可以让一些需要包含特殊字符的内容,统一进行原样输出。

    <![CDATA[
            <html><head>head</head><body>body</body></html>
        ]]>
    

    处理指令

    作用:告诉xml解析器如何解析xml内容

    <?xml-stylesheet type="text/css"  href="1.css" ?>

    完整例子:

    <?xml version="1.0" encoding="utf-8"?>
     <codes>
    	 <code>
    		<p>段落</p>
    		<p>段落</p>
    	</code>
    	<code>
    	<![CDATA[
    		<html><head>head</head><body>body</body></html>
    	]]>
    	</code>
    </codes>


    二、xml解析的方式

    有DOM解析和SAX解析方式。

    Dom解析常用工具有:

    1. JAXP (oracle官方)
    2. JDOM
    3. DOM4J(常用)
    SAX解析常用工具有:Sax解析工具(oracle官方)
    xml解析和sax解析的对比:(面试常考)


    三、DOM解析

    原理

    xml解析器一次性把整个xml文档加载进内存,然后再内存中构建一棵Document的对象树,通过Document对象,得到树的节点对象,通过节点对象访问到xml文档的内容。不适合读取大容量的文件,容易导致内存溢出。

    DOM4J工具

    需要导包。

    1、创建一个xml解析器对象

            SAXReader reader=new SAXReader();
    

    2、读取xml文档,返回Document对象

            Document doc=reader.read(new File("./src/contact.xml"));
    

    示例代码:

    	public static void main(String[] args) {
    		
    		try {
    			//1、创建一个xml解析器对象
    			SAXReader reader=new SAXReader();
    			//2、读取xml文档,返回Document对象
    			Document doc=reader.read(new File("./src/contact.xml"));
    			System.out.println(doc);
    		
    		} catch (DocumentException e) {
    			e.printStackTrace();
    			throw new RuntimeException(e);
    		}
    	}

    Dom4j读取xml文件

    节点:

    Iterator  Element.nodeIterator();  //获取当前标签节点下的所有子节点
    

    示例代码:

                       //用nodeIterator(),得到当前节点下的所有子节点对象
    			Iterator<Node> it=doc.nodeIterator();
    			while(it.hasNext()){
    				Node node=it.next();
    				String name=node.getName();
    				System.out.println(name);
    				
    				//继续取出其下面的子节点
    				//只有标签节点才有子节点
    				if(node instanceof Element){
    					Element elem=(Element) node;
    					Iterator<Node> it2=elem.nodeIterator();
    					while(it2.hasNext()){
    						Node n2=it2.next();
    						System.out.println(n2.getName());
    					}
    				}
    			}


    标签:

     Element  Document.getRootElement();  //获取xml文档的根标签 
    Element Element.element("标签名");//指定名称的第一个子标签
    Iterator<Element> iterator = list.iterator();
    

    示例代码:

    public void test3() throws DocumentException {
    		SAXReader reader=new SAXReader();
    		Document doc=reader.read(new File("./src/contact.xml"));
    		
    		Element rootElem=doc.getRootElement();
    		String name=rootElem.getName();
    		
    		System.out.println(name);
    		//得到当前标签下指定名称的第一个子标签
    		//Element contactElem=rootElem.element("contact");
    		//System.out.println(contactElem.getName());
    		
    		//得到当前标签下指定名称的所有子标签
    		Iterator<Element> it=rootElem.elementIterator("contact");
    		while(it.hasNext()){
    			Element elem=it.next();
    			System.out.println(elem.getName());
    		}
    		List<Element> list=rootElem.elements();
    		//遍历List的方法:普通for,增强for,迭代器
    		for(int i=0;i<list.size();i++){
    			Element e=list.get(i);
    			System.out.println(e.getName());
    		}
    		Iterator<Element> iterator = list.iterator();
    		while(it.hasNext()){
    			Element elem=it.next();
    			System.out.println(elem.getName());
    		}
    		
    		//想要获取更深层次的标签,只能一层层的读取
    		Element nameElem=doc.getRootElement().element("contact").element("name");
    		System.out.println(nameElem.getName());
    		
    	}

    属性:

    		String   Element.attributeValue("属性名") //获取指定名称的属性值
                     Attribute:    Element.attribute("属性名");//获取指定名称的属性对象    
                                  Attribute.getName()  //获取属性名称
                                  Attibute.getValue()  //获取属性值
                    List<Attribute>  Element.attributes();  //获取所有属性对象          
                    Iterator<Attribute>     Element.attibuteIterator(); //获取所有属性对象
    

    示例代码:

    //获取属性,先获取属性所在的标签对象,然后才能获取属性
    		Element contactElem=doc.getRootElement().element("contact");
    		String idValue=contactElem.attributeValue("id");
    		System.out.println(idValue);
    		
    		//得到属性对象
    		Attribute idAttr=contactElem.attribute("id");
    		System.out.println(idAttr.getName()+"="+idAttr.getValue());
    		
    		
    		//得到所有属性的对象,使用List
    		List<Attribute> list=contactElem.attributes();
    		for (Attribute attribute : list) {
    			System.out.println(attribute.getName()+"="+attribute.getValue());
    		}
    		//使用迭代器
    		Iterator<Attribute>  it=contactElem.attributeIterator();
    		while(it.hasNext()){
    			Attribute attr=it.next();
    			System.out.println(attr.getName()+"="+attr.getValue());
    		}

    文本:

    Element.getText();  //获取当前标签的文本
                            Element.elementText("标签名") //获取当前标签的指定名称的子标签的文本内容
    

    示例代码:

    	public void test5() throws DocumentException{
    		SAXReader reader=new SAXReader();
    		Document doc=reader.read(new File("./src/contact.xml"));
    		
    		//空格和换行也是有内容的
    		
    		//获取文本,要先获取标签,再获取标签上的文本
    		Element nameElem=doc.getRootElement().element("contact").element("name");
    		
    		String text=nameElem.getText();
    		System.out.println(text);
    		
    		String text2=doc.getRootElement().element("contact").elementText("name");
    		System.out.println(text2);
    		
    	}


    Dom4j修改xml文档

    写出内容到xml文档

    new XMLWriter(OutputStream,OutputFormat)

    writer(Document)

    	<pre name="code" class="java">                     Document doc=new SAXReader().read(new File(".src/contact.xml"));
    		
    		              //指定文件输出位置
    				FileOutputStream out=new FileOutputStream("D:/contact.xml");
    				//创建写出对象
    				//紧凑的
    				OutputFormat  format=OutputFormat.createCompactFormat();
    				OutputFormat  format1=OutputFormat.createPrettyPrint();
    				
    				//影响了xml文档保存时的编码和xml文档申明的编码,使用该方法生成的xml避免了乱码问题
    				format.setEncoding("utf-8");
    				
    				XMLWriter writer=new XMLWriter(out,format);
    				
    				writer.write(doc);
    				writer.close();

    
    

    修改xml文档的API

    增加:

    DocumentHelper.createDocument()
    addElement("contact");
    
    addAttribute("id", "001");
    

    //增加一个标签
    		Element rootElem=doc.addElement("contactList");
    		Element contactElem=rootElem.addElement("contact");
    		contactElem.addElement("name");
    		
    		//增加属性
    		contactElem.addAttribute("id", "001");
    		contactElem.addAttribute("name", "aa");


    修改: setValue(),setText()

    Element contactElem=doc.getRootElement().element("contact");
    		
    		//得到属性对象
    		Attribute idAttr=contactElem.attribute("id");
    		//修改属性值
    		idAttr.setValue("003");
    		
    		Element contactElem1=doc.getRootElement().element("contact");
    		contactElem1.addAttribute("id", "004");
    		
    		//修改文本
    		Element nameElem=doc.getRootElement().element("contact").element("name");
    		nameElem.setText("锤子");

    删除: deatch()

    //删除标签对象
    		/*Element ageElem=doc.getRootElement().
    				element("contact").element("age");
    		ageElem.detach();*/
    		//ageElem.getParent().remove(ageElem);
    		
    		//删除属性
    		Element contactElem=(Element) doc.getRootElement().elements().get(0);
    		
    		Attribute idAttr=contactElem.attribute("id");
    		idAttr.detach();

    四、XPATH
      

    当使用dom4j查询比较深的层次的时候非常麻烦。可以快速查找信息。 主要用于快速获取节点对象。

    XPath使用一个紧凑的、非XML语法方便使用在uri和XML属性值的XPath。XPath操作基于XML文档的逻辑结构,而不是其表面的语法。Xpath的名字来自其使用的符号在URL路径通过一个XML文档的层次结构导航。 除了用于定位,XPath还设计有一个真子集,可用于匹配(测试一个节点是否符合一个模式);使用XPath进行XSLT。

    XPath模型的XML文档的节点树。有不同类型的节点,包括元素节点、属性节点和文本节点。XPath定义了一个方法来计算每个节点类型字符串值。某些类型的节点也有名字。XPath完全支持XML命名空间的XML名称] [。因此,一个节点的名称被建模为一个地方的部分和一个可能的空命名空间URI;这就是所谓的扩展名。在[ 5数据模型]中详细描述了数据模型。

    1. 导包:jaxen-1.1-beta.jar
    2. 使用xpath的方法:

      List selectNodes();//查询多个节点对象 Node selectSingleNode("xpath表达式");//查询一个节点对象

    xpath的语法

    1. / ,绝对路径 ,表示从xml的跟位置开始或者子元素(一个层次结构)
    2. // ,相对路径,表示不分任何层次结构的选择元素
    3. *,通配符,表示匹配所有元素
    4. [],条件,表示选择什么条件下的元素
    5. @,属性,表示选择属性节点
    6. and ,关系,表示条件的与关系(等价于&)
    7. text(),文本,表示选择文本内容

    示例代码:
    public static void main(String[] args) throws DocumentException {
    		Document doc = new SAXReader().read(new File("./src/contact.xml"));
    
    		String xpath = "";
    		xpath="/contactList";
    		xpath="/contactList/contact";
    		xpath="//contact/name";
    		xpath="//name";
    		
    		//通配符
    		xpath="/contactList/*";
    		xpath="/contactList//*";
    		
    		//条件
    		xpath="//contact[@id]";
    		//第二个contact标签
    		xpath="//contact[2]";
    		xpath="//contact[last()]";
    		
    		//属性
    		xpath="//@id";  //选取的是id属性节点对象,返回Attribute对象
    		xpath="//contact[not(@id)]";
    		//选取id属性为002d contact标签
    		xpath="//contact[@id='002']";
    		xpath="//contact[@id='001' and @name='aa']";
    		
    		//选取文本内容
    		xpath="//name/text()";  //返回Text对象
    		xpath="//contact/name[text()='张三']";
    		
    		
    		List<Node> list = doc.selectNodes(xpath);
    		for (Node node : list) {
    			System.out.println(node);
    		}
    
    	}
    
    五、SAX解析

    原理

    读取加载处理都是一部分一部分的进行的,对内存要求比较低。

    AX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。

    SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器: 解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。 解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。 事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理


    核心API

    1. SAXParser:用于读取和解析xml文件
    2. parse()方法,用于解析xml文件。parse(File f,DefaultHandler dh)方法,解析xml文件。

    3. 参数1:File:表示读取xml文件

    4. 参数2:DefaultHandloer:SAX事件处理程序

                        void startDocument()  :  在读到文档开始时调用
                        void endDocument()  :在读到文档结束时调用
                        void startElement(String uri, String localName, String qName, Attributes attributes)  :读到开始标签时调用                
                        void endElement(String uri, String localName, String qName)   :读到结束标签时调用
                        void characters(char[] ch, int start, int length)  : 读到文本内容时调用
    

    示例代码:

    </pre><pre name="code" class="java">public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
    		SAXParser parser=SAXParserFactory.newInstance().newSAXParser();
    
    		MyDefalutHandler3  handler=new MyDefalutHandler3();
    		parser.parse(new File("./src/contact.xml"), handler);
    
    		List<Contact>  list=handler.getList();
    		for (Contact contact : list) {
    			System.out.println(contact);
    		}
    		
    	}
    public class MyDefalutHandler3 extends DefaultHandler {
    
    	private List<Contact> list = new ArrayList<Contact>();
    
    	public List<Contact> getList() {
    		return list;
    	}
    
    	private Contact contact;
    	private String curTag;
    	// 开始标签
    	@Override
    	public void startElement(String uri, String localName, String qName,
    			Attributes attributes) throws SAXException {
    		curTag=qName;
    		// 读取到contact的开始标签创建Contact对象
    		if ("contact".equals(qName)) {
    			contact = new Contact();
    
    			// 设置id值
    			contact.setId(attributes.getValue("id"));
    		
    		}
    	}
    
    	// 文本内容
    	@Override
    		public void characters(char[] ch, int start, int length) throws SAXException {
    			//当前文本内容
    			String content=new String(ch,start,length);
    			
    			if("name".equals(curTag)){
    				contact.setName(content);
    			}
    			if("age".equals(curTag)){
    				contact.setAge(content);
    			}
    			if("phone".equals(curTag)){
    				contact.setPhone(content);
    			}
    			if("email".equals(curTag)){
    				contact.setEmail(content);
    			}
    			if("qq".equals(curTag)){
    				contact.setQq(content);
    			}
    		}
    
    	// 结束标签
    	@Override
    	public void endElement(String uri, String localName, String qName)
    			throws SAXException {
    		// 读到contact的结束标签则放入list中
    		curTag=null;
    		if ("contact".equals(qName)) {
    			list.add(contact);
    		}
    	}
    
    }

    六、schema约束

    XML Schema 也是一种用于定义和描述 XML 文档结构与内容的模式语言,其出现是为了克服 DTD 的局限性

    XML Schema 文件自身就是一个XML文件,但它的扩展名通常为.xsd。支持名称空间。 一个XML Schema文档通常称之为模式文档(约束文档),遵循这个文档书写的xml文件称之为实例文档。

    和XML文件一样,一个XML Schema文档也必须有一个根结点,但这个根结点的名称为schema。

    编写了一个XML Schema约束文档后,通常需要把这个文件中声明的元素绑定到一个URI地址上,在XML Schema技术中有一个专业术语来描述这个过程,即把XML Schema文档声明的元素绑定到一个名称空间上,以后XML文件就可以通过这个URI(即名称空间)来告诉解析引擎,xml文档中编写的元素来自哪里,被谁约束。

    学习目标:不需要我们编写xsd 重点:根据xsd编写出xml文档。 难点:在xml中引入xsd约束

    基本操作步骤:

    a、根据xsd文件,找到根元素

    <?xml version="1.0" encoding="UTF-8"?>
    <书架>
    
    </书架>
    

    b、根元素来在哪个名称空间 使用xmlns关键字来声明名称空间。

    <?xml version="1.0" encoding="UTF-8"?>
    <tf:书架 xmlns:tf="http://www.tianfang1314.cn">
    
    </tf:书架>
    

    c、名称空间和哪个xsd文件对应

    <?xml version="1.0" encoding="UTF-8"?>
    <tf:书架 xmlns:tf="http://www.tianfang1314.cn"
        schemaLocation="http://www.tianfang1314.cn book.xsd">
    
    </tf:书架>
    

    d、schemaLocation来自一个标准的名称空间:固定写法

    <?xml version="1.0" encoding="UTF-8"?>
    <tf:书架 xmlns:tf="http://www.tianfang1314.cn"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.tianfang1314.cn book.xsd">
    
    </tf:书架>


    总结:
    XML现在已经成为一种通用的数据交换格式,它的平台无关性,语言无关性,系统无关性,给数据集成与交互带来了极大的方便。xml是一种重要的知识点,需要多练习才能进一步的掌握。其实这些东西说难不难,说易烨不易,主要是很多细节上面的东西,希望可以多查看帮助文档来进一步了解,常用的几种格式要掌握,如果想要进进一步加强理解可以查看:http://blog.csdn.net/sdksdk0/article/details/50749326

    源码地址:


  • 相关阅读:
    Codeforces 1291 Round #616 (Div. 2) B
    总结
    刷新DNS解析缓存+追踪+域名解析命令
    数学--数论--Hdu 5793 A Boring Question (打表+逆元)
    Lucene.net(4.8.0) 学习问题记录六:Lucene 的索引系统和搜索过程分析
    LeetCode 117 Populating Next Right Pointers in Each Node II
    LeetCode 116 Populating Next Right Pointers in Each Node
    test test
    LeetCode 115 Distinct Subsequences
    LeetCode 114. Flatten Binary Tree to Linked List
  • 原文地址:https://www.cnblogs.com/xiaowangba/p/6314839.html
Copyright © 2020-2023  润新知