XML解析

1、xml是标记型文档,而js使用dom解析标记型文档,解析原理:根据html的层级结构,在内存中分配一个树形结构,把html的标签】属性和文本都封装成对象,分别为:document对象、element对象、属性对象、文本duix,Node节点对象。xml的解析方式(技术):dom和sax

2、使用dom方式解析时,如果文件过大,会造成内存溢出,优点是易于实现增删改操作。

sax解析过程:采用事件驱动,边读边接续:从上到下,一行行解析,解析到某个对象,就把对象名称返回。使用sax方式实现查询不会造成内存溢出,但不能实现增删改操作。

3、通过API方式提供的解析器

sun公司,提供的针对dom和sax方式的解析器:jaxp

dom4j组织,提供的针对dom和sax方式的解析器:dom4j(在实际开发中使用最多)

jdom组织,提供的针对dom和sax方式的解析器:jdom

4、jaxp的API查看

>jaxp是JavaSE的一部分,在:

Module java.xml
Package javax.xml.parsers

中,其中四个类分别是针对dom和sax解析使用的类:

dom:

public abstract class DocumentBuilder extends Object解析器类

public abstract class DocumentBuilderFactory extends Object解析工厂

>抽象类不能通过new关键字实例化,所以其实例通过解析工厂中方法获取:public abstract DocumentBuilder newDocumentBuilder​() throws ParserConfigurationException

而解析工厂类的实例则通过可中的静态方法获取:public static DocumentBuilderFactory newInstance​()

>在解析器类中获取待解析文件的方法:(接收文件、字符串路径、字符流)

public Document parse​(File f) throws SAXException,IOException

注意返回的Document是一个接口,父接口是Node(public interface Document extends Node)

Document接口中的方法:得到标签、创建标签、创建文本、把文本添加到标签下面、删除节点等方法,例:

NodeList getElementsByTagName​(String tagname)

该方法返回值是NodeList型,而NodeList接口中有两个方法:一个是getLength()获取集合长度,另一个是item(int index)方法,根据索引值获取集合中项元素

>对xml文件进行修改操作后,需要回写,否则在原文件中查看不到:通过回写工厂类实例化的回写类:TransformerFactory tfactory = TransformerFactory.newInstance();

回写类中的回写方法:public abstract void transform​(Source xmlSource,Result outputTarget) throws TransformerException

其参数类型:public interface Source,其实现类之一:DOMSource类,构造方法可接收Node类型参数。

代码示例:

person.xml

<?xml version="1.0" encoding="UTF-8"?>
<person>
    <p1>
        <name>zhangsan</name>
        <age>16</age>
    </p1>
    <p1>
        <name>lisi</name>
        <age>20</age>
    </p1>
    <p1>
        <name>wangwu</name>
        <age>19</age>
    </p1>
</person>

PersonTestJaxp.java

import java.io.IOException;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;

/**
 * 实现jaxp操作xml
 * @author 17864
 */
public class PersonTestJaxp {
    public static void main(String[] args) throws Exception {
        selectAll() ;
        selectSin() ;
        addSex() ;
        modifyAge() ;
        // deleteAge() ;
        listElement() ;
    }
    //查询所有name元素的值
    private static void selectAll() throws ParserConfigurationException, SAXException, IOException {
        //1.创建解析工厂 alt+/ 代码提示
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance() ;
        //2.创建解析器
        DocumentBuilder db = dbf.newDocumentBuilder() ;
        //3.解析xml返回document(注意包w3c)
        Document d = db.parse("src/person.xml") ;
        //4.得到name元素
        NodeList list = d.getElementsByTagName("name") ;
        //5.遍历集合
        for(int i = 0 ; i < list.getLength() ; i ++) {
            //得到每一个name元素,Node类型
            Node name = list.item(i) ;
            //得到name元素中的值,String类型,输出快捷键 syso+alt+/
            System.out.println(name.getTextContent()) ;
        }
    }
    //获取第一个name元素的值
    public static void selectSin() throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance() ;
        DocumentBuilder db = dbf.newDocumentBuilder() ;
        Document d = db.parse("src/person.xml") ;
        NodeList list = d.getElementsByTagName("name") ;
        System.out.println("获取第一个name元素的值:" + list.item(0).getTextContent()) ;
    }
    //使用JAXP添加节点——对xml文件进行修改操作后,需要回写,否则在原文件中查看不到
    public static void addSex() throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance() ;
        DocumentBuilder db = dbf.newDocumentBuilder() ;
        Document d = db.parse("src/person.xml") ;
        //得到第一个p1
        Node p1 = d.getElementsByTagName("p1").item(0) ;
        //创建sex标签
        Element sex = d.createElement("sex") ;
        //创建文本
        Text text = d.createTextNode("female") ; //先创建再添加
        //把文本添加到标签下
        sex.appendChild(text) ;
        //把标签添加到p1下
        p1.appendChild(sex) ;
        //实例化回写对象
        TransformerFactory tff = TransformerFactory.newInstance() ;
        Transformer tf = tff.newTransformer() ;
        //回写方法:public abstract void transform​(Source xmlSource,Result outputTarget) throws TransformerException参数是接口类型,要找到其实现类传参
        tf.transform(new DOMSource(d), new StreamResult("src/person.xml"));
    }    
    //修改第一个p1下面的age为100
    public static void modifyAge() throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance() ;
        DocumentBuilder db = dbf.newDocumentBuilder() ;
        Document d = db.parse("src/person.xml") ;
        Node age = d.getElementsByTagName("age").item(0) ;
        age.setTextContent("100");
        TransformerFactory tff = TransformerFactory.newInstance() ;
        Transformer tf = tff.newTransformer() ;
        tf.transform(new DOMSource(d), new StreamResult("src/person.xml"));            
    }
    //删除第二个p1下的age节点
    public static void deleteAge() throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance() ;
        DocumentBuilder db = dbf.newDocumentBuilder() ;
        Document d = db.parse("src/person.xml") ;
        Node age = d.getElementsByTagName("age").item(1) ;
        Node p1 = age.getParentNode() ; //删除节点时必须找到其父节点
        p1.removeChild(age) ;
        TransformerFactory tff = TransformerFactory.newInstance() ;
        Transformer tf = tff.newTransformer() ;
        tf.transform(new DOMSource(d), new StreamResult("src/person.xml"));                
    }
    //遍历节点
    public static void listElement() throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance() ;
        DocumentBuilder db = dbf.newDocumentBuilder() ;
        Document d = db.parse("src/person.xml") ;
        list(d) ;
    }
    private static void list(Node node) { //参数向上转型
        //判断节点是否为元素类型,是,打印,否则,会将空格换行等内容全部都打印输出
        if(node.getNodeType() == Node.ELEMENT_NODE) {
            System.out.println(node.getNodeName()) ;
        }
        //得到一层子节点
        NodeList list = node.getChildNodes() ;
        //遍历list
        for(int i = 0 ; i < list.getLength() ; i ++) {
            Node node1 = list.item(i) ;
            list(node1) ; //递归
        }
    }
}

5、sax解析

>sax是JavaSE的一部分,在:

Module java.xml
Package javax.xml.parsers

中,其中四个类分别是针对dom和sax解析使用的类,支持sax的两个类:

public abstract class SAXParser extends Object解析器类

public abstract class SAXParserFactory extends Object解析工厂

>SAXParser类实例通过SAXParserFactory.newSAXParser()方法获得。类中解析方法:

public void parse​(File f,DefaultHandler dh) throws SAXException, IOException第一个参数是xml路径,第二个参数是事件处理器

当遇到不同类型标签时sax解析器会自动执行不同的方法:

当解析到开始标签时,执行:其中qName返回标签名

public void startElement​(String uri,
                         String localName,
                         String qName,
                         Attributes attributes)
                  throws SAXException

解析到文本时执行:

public void characters​(char[] ch,
                       int start,
                       int length)
                throws SAXException

解析到结束标签时执行:

public void endElement​(String uri,
                       String localName,
                       String qName)
                throws SAXException

>使用schema的sax方式解析xml(sax方式解析只能做查询操作,不能实现增删改)

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class TestSax {
    public static void main(String[] args) throws Exception {
        SAXParserFactory sf = SAXParserFactory.newInstance() ;
        SAXParser s = sf.newSAXParser() ;
        s.parse("src/person.xml", new MyDefault()); //事件处理器需要自己创建一个类,继承DefaultHandler,在类中重写三个方法
    }
}
class MyDefault extends DefaultHandler {
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        System.out.print("<" + qName + ">");
    }
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        System.out.print(new String(ch,start,length));
    }
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        System.out.print("</" + qName + ">");
    }    
}
//获取所有的name元素值
class MyDefault2 extends DefaultHandler {
    boolean flag = false ;
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        //判断qName是否是name元素
        if("name".equals(qName)) {
            flag = true ;
        }
    }
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        //当flag值是true时表示解析到name元素
        if(flag == true) {
            System.out.println(new String(ch,start,length));
        }
    }
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        //把flag设置成false,表示name元素结束
        if("name".equals(qName)) {
            flag = false ;
        }
    }    
}

6、使用dom4j解析器(性能比jdom好)解析xml

>dom4j不是JavaSE的一部分,所以使用dom4j需要导入jar包(dom4j-1.6.1.jar)

导包:将jar包粘贴入lib文件夹(新建Folder)下,然后选中jar包→右键选择Build Path→Add to Build Path

>得到document:
    SAXReader reader = new SAXPeader();
    Document document = reader.read(url);

document的父接口是Node,其中有方法:

获取根节点getElement(),返回Element

Element也是一个接口,父接口是Node,其中有方法:

获取父节点:getParent();

直接在父节点下添加标签:addElement(String ele);

直接在标签后添加文本内容:setText(String text);

回写操作:

OutputFormat format = OutputFormat.createPrettyPrint() ; //格式化OutputFormat,有缩进效果
XMLWriter xmlWriter = XMLWriter(new FileOutputStream("src/person.xml"), format) ;
xmlWriter.write(document) ;
xmlWriter.close() ; //关闭流

>使用dom4j查询xml

//查询xml中所有name元素的值
    public static void selectName() {    
        //创建解析器
        SAXReader saxReader = new SAXReader();
        //得到document
        Document document = saxReader.read(url);
        //得到根节点
        Element root = document.getRootElement() ;
        //得到p1标签
/*
 * 得到标签:
 * element(qName):表示获取标签下面的指定子标签,如p1标签下的name标签
 * elements(qName):表示获取标签下面所有指定子标签(一层),如得到所有的根标签下的p1标签,返回一个list集合,获取List结合中元素使用get(int index)方法
 * elements():获取标签下面的所有一层子标签
 * getText()得到元素中的文本内容
 */
        List<Element> list = root.elements("p1") ;
        //遍历list
        for(Element element : list) {
            //得到p1下面的name元素
            Element name = element.element("name") ;
            //得到name元素中值输出
            System.out.println(name.getText());
        }     
    }

>在指定位置添加节点的核心代码:

创建元素:Element school = DocumentHelper.createElement("school") ;

给新创建的元素设置文本内容:school.setText("ecit") ;

获取根元素下第一个p1元素下的所有元素:List<Element> list = p1.elements() ;

在特定位置添加元素:list.add(1,school);

回写

注:可以对得到document的操作和回写操作封装成方法。还可以将要传递的文件路径封装成静态常量。

>使用dom4j实现修改操作的核心代码:得到元素后直接setText(String str)

>使用dom4j实现删除操作的核心代码:

删除也是需通过父节点删除:

知道根节点p1是school标签的父节点:p1.remove(sch); //sch是获取到的school元素Element sch = p1.element("school");

需要获取标签的父节点:Element p = sch.getParent();然后删除

回写

>使用dom4j获取属性的核心代码:

得到标签元素后,根据标签元素的属性名称获取属性值p1.attributeValue("id1")

7、使用dom4j支持XPATH操作:可以直接获取到某个元素,不用一层层解析

>使用形式:

/A/B/C:表示层级,A标签下的B标签下的C标签

//B:表示标签名为B的所有标签

/*:表示所有标签

B[1]:表示第一个B标签

B[last()]:表示左后一个B标签

//B[@id]:表示所有有id属性的B标签

//B[@id='b1']:表示所有有id属性且属性值为b1的B标签

>默认情况下dom4j是不支持xpath的,若要使用则需要导入jar包:jaxen-1.1-beta-6.jar

dom4j中提供的两个支持xpath的方法:

获取多个节点:List<Node> selectNodes("xpath表达式")

获取单个节点:Node selectSingleNode("xpath表达式")

(获取节点元素中文本内容通过getText()方法)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值