从零开始学XML(修订版)(二)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 笔记

删除


现在我要删除的是beijing这个节点!

private static void delete(Document document) throws TransformerException {
    //获取到beijing这个节点
    Node node = document.getElementsByTagName("beijing").item(0);
    //获取到父节点,然后通过父节点把自己删除了
    node.getParentNode().removeChild(node);
    //把内存中的Dom树更新到硬盘文件中
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer transformer = transformerFactory.newTransformer();
    transformer.transform(new DOMSource(document), new StreamResult("city.xml"));
}
  • 效果:

16.png


修改


将guangzhou节点的文本内容修改成广州你好

private static void update(Document document) throws TransformerException {
    //获取到guangzhou节点
    Node node = document.getElementsByTagName("guangzhou").item(0);
    node.setTextContent("广州你好");
    //将内存中的Dom树更新到硬盘文件中
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer transformer = transformerFactory.newTransformer();
    transformer.transform(new DOMSource(document), new StreamResult("city.xml"));
}
  • 效果:

17.png



操作属性


XML文档是可能带有属性值的,现在我们要guangzhou节点上的属性

private static void updateAttribute(Document document) throws TransformerException {
    //获取到guangzhou节点
    Node node = document.getElementsByTagName("guangzhou").item(0);
    //现在node节点没有增加属性的方法,所以我就要找它的子类---Element
    Element guangzhou = (Element) node;
    //设置一个属性,如果存在则修改,不存在则创建!
    guangzhou.setAttribute("play", "gzchanglong");
    //如果要删除属性就用removeAttribute()方法
    //将内存中的Dom树更新到硬盘文件中
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer transformer = transformerFactory.newTransformer();
    transformer.transform(new DOMSource(document), new StreamResult("city.xml"));
}
  • 效果:

18.png



SAX解析


SAX采用的是一种顺序的模式进行访问,是一种快速读取XML数据的方式。当时候SAX解析器进行操作时,会触发一系列事件SAX。采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器

sax是一种推式的机制,你创建一个sax 解析器,解析器在发现xml文档中的内容时就告诉你(把事件推给你). 如何处理这些内容,由程序员自己决定。

当解析器解析到<?xml version="1.0" encoding="UTF-8" standalone="no"?>声明头时,会触发事件。解析到<china>元素头时也会触发事件!也就是说:当使用SAX解析器扫描XML文档(也就是Document对象)开始、结束,以及元素的开始、结束时都会触发事件,根据不同事件调用相对应的方法!

19.jpg


首先我们还是先拿到SAX的解析器再说吧!

//要得到解析器对象就需要造一个工厂,于是我造了一个工厂
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
//获取到解析器对象
SAXParser saxParse = saxParserFactory.newSAXParser();
  • 调用解析对象的解析方法的时候,需要的不仅仅是XML文档的路径!还需要一个事件处理器!

20.png

  • 事件处理器都是由我们程序员来编写的,它一般继承DefaultHandler类,重写如下5个方法:
@Override
public void startDocument() throws SAXException {
    super.startDocument();
}
@Override
public void endDocument() throws SAXException {
    super.endDocument();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
    super.startElement(uri, localName, qName, attributes);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
    super.endElement(uri, localName, qName);
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
    super.characters(ch, start, length);
}
  • 获取解析器,调用解析器解析XML文档的代码:
public static void main(String[] args) throws Exception{
    //要得到解析器对象就需要造一个工厂,于是我造了一个工厂
    SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
    //获取到解析器对象
    SAXParser saxParse = saxParserFactory.newSAXParser();
    //获取到XML文档的流对象
    InputStream inputStream = SAXParse.class.getClassLoader().getResourceAsStream("city.xml");
    saxParse.parse(inputStream, new MyHandler());
}
  • 事件处理器的代码:
public class MyHandler extends DefaultHandler {
    @Override
    public void startDocument() throws SAXException {
        System.out.println("我开始来扫描啦!!!!");
    }
    @Override
    public void endDocument() throws SAXException {
        System.out.println("我结束了!!!!");
    }
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        //如果要解析出节点属性的内容,也非常简单,只要通过attributes变量就行了!
        //输出节点的名字!
        System.out.println(qName);
    }
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        System.out.println(qName);
    }
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        System.out.println(new String(ch,start,length));
    }
}
  • 我们发现,事件处理器的代码都非常简单,然后就如此简单地就能够遍历整个XML文档了!
  • 如果要查询单独的某个节点的内容也是非常简单的哟!只要在startElement()方法中判断名字是否相同即可!
  • 现在我只想查询guangzhou节点的内容:
//定义一个标识量,用于指定查询某个节点的内容
boolean flag = false;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
    //如果节点名称是guangzhou,我才输出,并且把标识量设置为true
    if (qName == "guangzhou") {
        System.out.println(qName);
        flag = true;
    }
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
    //只有在flag为true的情况下我才输出文本的内容
    if (flag == true) {
        System.out.println(new String(ch, start, length));
    }
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
    //在执行到元素的末尾时,不要忘了将标识量改成false
    if (qName == "guangzhou" && flag == true) {
        System.out.println(qName);
        flag = false;
    }
}
  • 效果:

21.png



DOM和SAX解析的区别:


DOM解析读取整个XML文档,在内存中形成DOM树,很方便地对XML文档的内容进行增删改。但如果XML文档的内容过大,那么就会导致内存溢出!

SAX解析采用部分读取的方式,可以处理大型文件,但只能对文件按顺序从头到尾解析一遍,不支持文件的增删改操作

DOM和SAX解析有着明显的差别,什么时候使用DOM或者SAX就非常明了了。


dom4j


Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使用的特点。


为什么需要有dom4j


  • dom缺点:比较耗费内存
  • sax缺点:只能对xml文件进行读取,不能修改,添加,删除
  • dom4j:既可以提高效率,同时也可以进行crud操作

因为dom4j不是sun公司的产品,所以我们开发dom4j需要导入开发包


获取dom4j的解析器


  • 使用dom4j对XML文档进行增删改查,都需要获取到dom4j的解析器
//获取到解析器
SAXReader saxReader = new SAXReader();
//获取到XML文件的流对象
InputStream inputStream = DOM4j.class.getClassLoader().getResourceAsStream("1.xml");
//通过解析器读取XML文件
Document document = saxReader.read(inputStream);


获取Document对象


我们都知道,Document代表的是XML文档,一般我们都是通过Document对象开始,来进行CRUD(增删改查)操作的!

获取Document对象有三种方式:

①:读取XML文件,获得document对象(这种最常用)

SAXReader reader = new SAXReader();
Document document = reader.read(new File("input.xml"));

②:解析XML形式的文本,得到document对象

String text = "<members></members>";
Document document=DocumentHelper.parseText(text);

③:主动创建document对象.

Document document =DocumentHelper.createDocument();
//创建根节点
Element root = document.addElement("members");


CRUD的重要一句话:


读取XML文档的数据,都是通过Document获取根元素,再通过根元素获取得到其他节点的,从而进行操作!

如果XML的结构有多层,需要一层一层地获取!


查询


@Test
public void read() throws DocumentException {
    //获取到解析器
    SAXReader saxReader = new SAXReader();
    //获取到XML文件的流对象
    InputStream inputStream = dom4j11.class.getClassLoader().getResourceAsStream("1.xml");
    //通过解析器读取XML文件
    Document document = saxReader.read(inputStream);
    //获取得到根节点
    Element root = document.getRootElement();
    //获取得到name节点
    Element name = root.element("name");
    //得到了name节点,就可以获取name节点的属性或者文本内容了!
    String text = name.getText();
    String attribute = name.attributeValue("littleName");
    System.out.println("文本内容是:" + text);
    System.out.println("属性内容是:" + attribute);
}
  • XML文件如下:
<?xml version="1.0" encoding="UTF-8" ?>
     <person>
    <name littleName="fucheng">zhongfucheng</name>
    <age>20</age>
</person>
  • 效果:

22.png

  • 多层结构的查询:
//获取得到根节点
Element root = document.getRootElement();
//一层一层地获取到节点
Element element = root.element("guangdong").element("guangzhou").element("luogang");
String value = element.getText();
System.out.println(value);
  • XML文件和结果:

23.png



增加


在DOM4j中要对内存中的DOM树写到硬盘文件中,也是要有转换器的支持的!

dom4j提供了XMLWriter供我们对XML文档进行更新操作,一般地创建XMLWriter的时候我们都会给出两个参数,一个是Writer,一个是OutputFormat

24.png

这个OutputFormat有什么用的呢?其实就是指定回写XML的格式和编码格式。细心的朋友会发现,上面我们在jaxp包下使用dom解析的Transformer类,把内存中的DOM树更新到文件硬盘中,是没有格式的!不信倒回去看看!这个OutputFormat就可以让我们更新XML文档时也能带有格式

//创建带有格式的对象
OutputFormat outputFormat = OutputFormat.createPrettyPrint();
//设置编码,默认的编码是gb2312,读写的编码不一致,会导致乱码的!
outputFormat.setEncoding("UTF-8");
//创建XMLWriter对象
XMLWriter xmlWriter = new XMLWriter(new FileWriter("2.xml"), outputFormat);
//XMLWriter对象写入的是document
xmlWriter.write(document);
//关闭流
xmlWriter.close();
  • 下面我们就为在person节点下新创建一个name节点吧,完整的代码如下:
@Test
public void add() throws Exception {
    //获取到解析器
    SAXReader saxReader = new SAXReader();
    //获取到XML文件的流对象
    InputStream inputStream = dom4j11.class.getClassLoader().getResourceAsStream("1.xml");
    //通过解析器读取XML文件
    Document document = saxReader.read(inputStream);
    //创建出新的节点,为节点设置文本内容
    Element newElement = DocumentHelper.createElement("name");
    newElement.setText("ouzicheng");
    //获取到根元素
    Element root = document.getRootElement();
    //把新创建的name节点挂在根节点下面
    root.add(newElement);
    //创建带有格式的对象
    OutputFormat outputFormat = OutputFormat.createPrettyPrint();
    //设置编码,默认的编码是gb2312,读写的编码不一致,会导致乱码的!
    outputFormat.setEncoding("UTF-8");
    //创建XMLWriter对象
    XMLWriter xmlWriter = new XMLWriter(new FileWriter("2.xml"), outputFormat);
    //XMLWriter对象写入的是document
    xmlWriter.write(document);
    //关闭流
    xmlWriter.close();
}
  • 效果如下,是有格式的

25.png


在指定的位置增加节点!现在我想的就是在age属性前面添加节点!

//创建一个新节点
Element element = DocumentHelper.createElement("name");
element.setText("ouzciheng");
//获取得到person下所有的节点元素!
List list = document.getRootElement().elements();
//将节点添加到指定的位置上
list.add(1, element);
  • 效果图:

26.png


修改


  • XMLWriter和获取Document对象的代码我就不贴出来了,反正都是一样的了!
//获取得到age元素
Element age = document.getRootElement().element("age");
age.setText("9999");
  • 效果如下:

27.png



删除


  • XMLWriter和获取Document对象的代码我就不贴出来了,反正都是一样的了!
//获取得到age节点
Element age = document.getRootElement().element("age");
//得到age节点的父节点,使用父节点的remove删除age节点!
age.getParent().remove(age);
  • 效果:

28.png


XPATH


什么是XPATH


XPath 是一门在 XML 文档中查找信息的语言。XPath 用于在 XML 文档中通过元素和属性进行导航。


为什么我们需要用到XPATH


上面我们使用dom4j的时候,要获取某个节点,都是通过根节点开始,一层一层地往下寻找,这就有些麻烦了

如果我们用到了XPATH这门语言,要获取得到XML的节点,就非常地方便了!



快速入门


使用XPATH需要导入开发包jaxen-1.1-beta-7,我们来看官方的文档来入门吧。

  • XPATH的文档非常国际化啊,连中文都有

29.jpg

  • XPATH文档中有非常多的实例,非常好学,对着来看就知道了!

30.jpg

  • 我们来用XPATH技术读取XML文件的信息吧,XML文档如下:

31.png

  • 之前,我们是先获取根节点,再获取guangdong节点再获取guangzhou节点,然后才能读取tianhe节点或者luogang节点的,下面我们来看一下使用XPATH可以怎么的便捷
//直接获取到luogang节点
org.dom4j.Node node =  document.selectSingleNode("//luogang");
//获取节点的内容
String value = node.getText();
System.out.println(value);
  • 效果:

32.png

获取什么类型的节点,XPATH的字符串应该怎么匹配,查文档就知道了,这里就不再赘述了。!


目录
相关文章
|
1月前
|
XML 存储 JavaScript
|
1月前
|
XML 存储 数据格式
|
6月前
|
XML 存储 数据格式
xml简介
xml简介
37 0
|
XML 设计模式 数据格式
XML基础入门:关于XML建模
XML基础入门:关于XML建模
46 0
|
XML 数据格式
XML入门二
XML入门二
66 0
|
XML 存储 缓存
XML入门三
XML入门三
64 0
|
XML 存储 JavaScript
XML入门一
XML入门一
71 0
|
XML 存储 数据格式
|
XML 数据格式
XML 简介(下)
XML 简介(下)
XML 简介(下)