XML解析

本文介绍了Java中配置文件的三种位置及读取方式,重点讲解了XML的使用,包括DOM和SAX解析方法。DOM解析形成树结构便于操作但消耗内存,适合小规模数据;SAX解析事件驱动,内存消耗小但编码复杂。此外,还涉及了XPath在DOM4J中的应用,展示了如何通过XPath选取XML节点。
摘要由CSDN通过智能技术生成

XML和properties

  1. Java中配置文件的三种配置位置及读取方式XML的作用

    • 配置 *.properties 键值对文件 *.xml *.ini .yaml/.yml

    • 数据交换

      • xml webservice

      • json

        • object { }

        • array [ ]

1.2 存放位置及读取方式 1.2.1 src根目录下或resources资源文件夹 Xxx.class.getResourceAsStream("/config.properties"); 1.2.2 与读取配置文件的类在同一包 Xxx.class.getResourceAsStream("config2.properties"); 1.2.3 WebContent(webroot)(或其子目录下)

request :HttpServletRequest

session: HttpSession

ServletContext application = this.getServletContext(); ​ InputStream is = application.getResourceAsStream("/WEB-INF/config3.properties");

InputStream is = application.getResourceAsStream("/upload/config3.properties");

  1. 解析properties文件

public static void main(String[] args) throws Exception{
    InputStream is = PropertiesTest.class.getResourceAsStream("/db.properties");
    Properties properties = new Properties();
    properties.load(is);
    String user = properties.getProperty("user");
    String password = properties.getProperty("password");
    System.out.println(user+":"+password);
}

xml解析方式(了解)

  • XML解析方式分为两种:DOM方式和SAX方式

DOM方式

  1. DOM:Document Object Model,文档对象模型。在应用程序中,基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称DOM树),应用程序正是通过对这个对象模型的操作,来实现对XML文档数据的操作。通过DOM接口,应用程序可以在任何时候访问XML文档中的任何一部分数据,因此,这种利用DOM接口的机制也被称作随机访问机制。

    优点:

    1、形成了树结构,有助于更好的理解、掌握,且代码容易编写。

    2、解析过程中,树结构保存在内存中,方便修改。

    缺点:

     1、由于文件是一次性读取,所以对内存的耗费比较大。

     2、如果XML文件比较大,容易影响解析性能且可能会造成内存溢出。

books.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
    <book id="1">
        <name>冰与火之歌</name>
        <author>乔治马丁</author>
        <year>2014</year>
        <price>89</price>
    </book>
    <book id="2">
        <name>安徒生童话</name>
        <year>2004</year>
        <price>77</price>
        <language>English</language>
    </book>    
</bookstore>

DOMTest文件

import java.io.InputStream;
​
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
​
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
​
public class DOMTest {
    public static void main(String[] args) throws Exception {
        // 创建一个DocumentBuilderFactory的对象
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        // 创建DocumentBuilder对象
        DocumentBuilder db = dbf.newDocumentBuilder();
        // 通过DocumentBuilder对象的parser方法加载books.xml文件到当前项目下
        InputStream is = DOMTest.class.getResourceAsStream("/books.xml");
        Document document = db.parse(is);
        // 获取所有book节点的集合
        NodeList bookList = document.getElementsByTagName("book");
        // 通过nodelist的getLength()方法可以获取bookList的长度
        System.out.println("一共有" + bookList.getLength() + "本书");
        // 遍历每一个book节点
        for (int i = 0; i < bookList.getLength(); i++) {
            System.out.println("=========下面开始遍历第" + (i + 1) + "本书的内容=========");
            // 通过 item(i)方法 获取一个book节点,nodelist的索引值从0开始
            Node book = bookList.item(i);
            // 获取book节点的所有属性集合
            NamedNodeMap attrs = book.getAttributes();
            System.out.println("第 " + (i + 1) + "本书共有" + attrs.getLength() + "个属性");
            // 遍历book的属性
            for (int j = 0; j < attrs.getLength(); j++) {
                // 通过item(index)方法获取book节点的某一个属性
                Node attr = attrs.item(j);
                // 获取属性名
                System.out.print("属性名:" + attr.getNodeName());
                // 获取属性值
                System.out.println("--属性值" + attr.getNodeValue());
            }
            // 解析book节点的子节点
            NodeList childNodes = book.getChildNodes();
            // 遍历childNodes获取每个节点的节点名和节点值
            System.out.println("第" + (i + 1) + "本书共有" + childNodes.getLength() + "个子节点");
            for (int k = 0; k < childNodes.getLength(); k++) {
                // 区分出text类型的node以及element类型的node
                if (childNodes.item(k).getNodeType() == Node.ELEMENT_NODE) {
                    // 获取了element类型节点的节点名
                    System.out.print("第" + (k + 1) + "个节点的节点名:" + childNodes.item(k).getNodeName());
                    // 获取了element类型节点的节点值
                    System.out.println("--节点值是:" + childNodes.item(k).getFirstChild().getNodeValue());
                    // System.out.println("--节点值是:" + childNodes.item(k).getTextContent());
                }
            }
            System.out.println("=========结束遍历第" + (i + 1) + "本书的内容=========");
        }
​
    }
}

SAX方式

  1. SAX:Simple API for XML。XML简单应用程序接口。SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件驱动接口。

    优点:

          1、采用事件驱动模式,对内存耗费比较小。

          2、适用于只处理XML文件中的数据时。

        缺点:

          1、编码比较麻烦。

          2、很难同时访问XML文件中的多处不同数据。

Book.java文件

public class Book {
    private String id;
    private String name;
    private String author;
    private String year;
    private String price;
    private String language;
    //省略get/set
}

SAXParserHandler.java文件

import java.util.ArrayList;
​
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
​
public class SAXParserHandler extends DefaultHandler {
    String value = null;
    Book book = null;
    private ArrayList<Book> bookList = new ArrayList<Book>();
    public ArrayList<Book> getBookList() {
        return bookList;
    }
    int bookIndex = 0;
    /**
     *  用来标识解析开始
     */
    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
        System.out.println("SAX解析开始");
    }
    
    /**
     * 用来标识解析结束
     */
    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
        System.out.println("SAX解析结束");
    }
    
    /**
     * 当一个文档元素开始时被调用
     */
    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        //调用DefaultHandler类的startElement方法
        super.startElement(uri, localName, qName, attributes);
        if (qName.equals("book")) {
            bookIndex++;
            //创建一个book对象
            book = new Book();
            //开始解析book元素的属性
            System.out.println("=========开始遍历某一本书的内容=========");
            //不知道book元素下属性的名称以及个数,如何获取属性名以及属性值
            int num = attributes.getLength();
            for(int i = 0; i < num; i++){
                System.out.print("book元素的第" + (i + 1) +  "个属性名是:"
                        + attributes.getQName(i));
                System.out.println("---属性值是:" + attributes.getValue(i));
                if (attributes.getQName(i).equals("id")) {
                    book.setId(attributes.getValue(i));
                }
            }
        }
        else if (!qName.equals("name") && !qName.equals("bookstore")) {
            System.out.print("节点名是:" + qName + "---");
        }
    }
    /**
     * 当一个文档元素结束时被调用
     */
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        //调用DefaultHandler类的endElement方法
        super.endElement(uri, localName, qName);
        //判断是否针对一本书已经遍历结束
        if (qName.equals("book")) {
            bookList.add(book);
            book = null;
            System.out.println("=========结束遍历某一本书的内容=========");
        }
        else if (qName.equals("name")) {
            book.setName(value);
        }
        else if (qName.equals("author")) {
            book.setAuthor(value);
        }
        else if (qName.equals("year")) {
            book.setYear(value);
        }
        else if (qName.equals("price")) {
            book.setPrice(value);
        }
        else if (qName.equals("language")) {
            book.setLanguage(value);
        }
    }
    
    /**
     * 调用处理XML文档元素的开始标签和结束标签之间的文本数据
     */
    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        super.characters(ch, start, length);
        value = new String(ch, start, length);
        if (!value.trim().equals("")) {
            System.out.println("节点值是:" + value);
        }
    }
}

SAXTest测试类

import java.io.InputStream;
​
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
​
public class SAXTest {
    public static void main(String[] args) throws Exception {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
        SAXParserHandler handler = new SAXParserHandler();
        InputStream is = SAXTest.class.getResourceAsStream("/books.xml");
        //解析
        parser.parse(is, handler);
        System.out.println("~!~!~!共有" + handler.getBookList().size() + "本书");
        for (Book book : handler.getBookList()) {
            System.out.println(book.getId());
            System.out.println(book.getName());
            System.out.println(book.getAuthor());
            System.out.println(book.getYear());
            System.out.println(book.getPrice());
            System.out.println(book.getLanguage());
            System.out.println("----finish----");
        }
    }
}

XML解析开发包

  • JAXP(Java API for XMLProcessing,意为XML处理的Java API):是SUN公司推出的解析标准实现。

  • Dom4j:是开源组织推出的解析开发包。(牛,大家都在用,包括SUN公司的一些技术的实现都在用)

  • JDom:是开源组织推出的解析开发包。

DOM4j&XPath

  1. 下载地址及官网

下载地址
https://dom4j.github.io/
  • dom4j-1.6.1.jar

  • jaxen-1.1-beta-6

    • Jaxen是一个Java编写的开源的XPath库,它适用于许多不同的对象模型,包括 DOM、XOM、dom4j 和 JDOM

    • XPath 使用路径表达式在 XML 文档中进行导航,是一个 W3C 标准

XPath

参考文档:XPath 教程 | 菜鸟教程

节点

  • 在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档(根)节点。

<?xml version="1.0" encoding="ISO-8859-1"?>
<bookstore>
    <book>
        <title lang="en">Harry Potter</title>
        <author>J K. Rowling</author> 
        <year>2005</year>
        <price>29.99</price>
    </book>
</bookstore>

  • <bookstore> (文档节点,根元素)

  • <author>J K. Rowling</author> (元素节点)

  • lang="en" (属性节点)

  • 基本值(文本)

    • J K. Rowling
       "en"
      
* 项目
  * 项目是基本值或者节点。
* 节点关系
  * 父(Parent)
  * 子(Children)
  * 同胞(Sibling)
  * 先辈(Ancestor)
  * 后代(Descendant)

选取节点

表达式描述
nodename选取此节点的所有子节点。
/从根节点选取。
//从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
.选取当前节点。
..选取当前节点的父节点。
@选取属性。
路径表达式结果
/bookstore/book[1]选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()]选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1]选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()<3]选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
//title[@lang]选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang='en']选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00]选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
/bookstore/book[price>35.00]/title选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。

DOM4J

有DOMReader和SAXReader两种方式。因为利用了相同的接口,它们的调用方式是一样的。

SAXReader

SAXReader saxReader = new SAXReader();
Document document = saxReader.read(参数);

Node

方法描述
public String getName()取得节点名称
public void setName(String name)设置节点名称
public Element getParent()取得父元素
public String getText()取得节点文本
public void setText(String text)设置节点内容
public void setParent(Element parent)设置父元素
public void write(Writer writer) throws IOException输出
List selectNodes(String xpathExpression)得到指定所有节点
Node selectSingleNode(String xpathExpression)得到单个节点

Document

Element root = document.getRootElement();
List<Element> nodeList = document.selectNodes(xpath);

Element

方法描述
Element element(String name)返回当前元素的指定名称的第一个子元素
List<Element> elements()返回当前元素的所有子元素
List<Element> elements(String name)返回当前元素的所有指定名称的子元素
Attribute attribute(String name)返回当前元素指定名称的属性
String attributeValue(String name)返回指定属性值,如果属性不存在,返回空字符串

示例代码,使用前面的book.xml文件

import java.io.InputStream;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class XpathTest {
	public static void main(String[] args) throws Exception  {
		InputStream is = Dom4jTest.class.getResourceAsStream("/books.xml");
		SAXReader saxReader = new SAXReader();
		Document document = saxReader.read(is);
		System.out.println("***选择所有name元素***");
		List<Element> list =  document.selectNodes("//name");
		for(Element e : list) {
			System.out.println(e.getName()+":"+e.getText());
		}
		System.out.println("***选择所有book元素id为2的name元素***");
		List<Element> list2 = document.selectNodes("/bookstore/book[@id=2]/name");
		for(Element e : list2) {
			System.out.println(e.getName()+":"+e.getText());
		}
	}
}

解析示例

  • config.xml文件

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

<config>
    <action path="/userRegAction" type="com.donkee.action.UserRegAction">
        <forward name="success" path="/reg.jsp" redirect="true" />
        <forward name="failed" path="/index.jsp" redirect="false" />
    </action>
    <action path="/userLoginAction" type="com.donkee.action.UserLoginAction">
        <forward name="success" path="/login.jsp" redirect="false" />
        <forward name="b" path="/welcome.jsp" redirect="true" />
    </action>
    <action path="/userAction" type="com.donkee.action.UserAction">
        <forward name="list" path="/user_list.jsp" redirect="false" />
        <forward name="b" path="/welcome.jsp" redirect="true" />
    </action>
</config>
  • 解析

public static void main(String[] args)throws Exception {
    InputStream is = Dom4jTest.class.getResourceAsStream("/config.xml");
    SAXReader saxReader = new SAXReader();
    Document document = saxReader.read(is);
    // /config/action:XPath语言
    //其中的第一个/为根节点
    List<Element> nodeList = document.selectNodes("/config/action");
    for (Element actionElement : nodeList) {
        //attributeValue根据元素属性名称得到属性值
        String path = actionElement.attributeValue("path");
        String type = actionElement.attributeValue("type");
        System.out.println(path + ":" + type);
        List<Element> forwardList = actionElement.selectNodes("forward");
        for (Element forwardElement : forwardList) {
            String name = forwardElement.attributeValue("name");
            String forwardPath = forwardElement.attributeValue("path");
            String redirect = forwardElement.attributeValue("redirect");
            System.out.println("\t"+name + ":" + forwardPath + ":" + redirect);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值