资讯专栏INFORMATION COLUMN

Java之XML解析

gclove / 3241人阅读

摘要:本篇讲在中的解析,最后会简单地讲在解析时的做法。解析器通过解析校验的文件,可以知道哪些元素没有文本节点的子元素,因此可以帮我们剔除空白字符。类将类进一步封装,用表示。当构造对象时,会自动解析出元素的元素名元素的属性等。

许多的Java框架都支持用户自己配置,其中很常见的就是使用XML文件进行配置。
本篇讲XML在Java中的解析,最后会简单地讲Mybatis在解析XML时的做法。
XML 文件




    
        
            
            
                
                
                
                
            
        
    

    
        
    

XML 文件较为常见的就是上边的样子

第一行是文档头

第二行是文档类型定义(DTD,有时是Schema。作用都是为了保证文档正确)

其余的就是元素

需要注意的地方

XML 是大小写敏感的

XML 的属性必须用引号括起来

XML 所有属性必须有值

Java DOM解析器

Java读入一个XML文件需要DocumentBuilder类,可以通过DocumentBuilderFactory类构建。

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();

之后就可以通过DocumentBuilder类的parse方法读入一个XML文件啦。
parse接受多种参数,如FileInputStream等。

InputStream stream 
   = Thread.currentThread().getContextClassLoader().getResourceAsStream("mybatis-config.xml");
Document document = builder.parse(stream);
   或        
File file = new File("src/main/resources/mybatis-config.xml");
Document document = builder.parse(file);

此时就已经可以使用了,需要注意的一点就是,元素之间的空白字符也会被认为是子元素。
在没有使用DTD或Schema的情况下,需要我们手动判断元素是否继承自Element
Node就是我们XML文件上的一个元素,Node类还有很多实用的方法,这里就不一一列举了。

// 获取根元素
Element root = document.getDocumentElement();
// 获取孩子元素
NodeList childNodes = root.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
    Node node = childNodes.item(i);
    if (node instanceof Element) {
        System.out.println(node.getNodeName() + " " + node.getTextContent());
    }
}        

如果使用了XML校验,也就是DTD或者Schema。在使用时可以进行设置。
解析器通过解析校验的文件,可以知道哪些元素没有文本节点的子元素,因此可以帮我们剔除空白字符。

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 开启校验
factory.setValidating(true);
// 忽略空白字符
factory.setIgnoringElementContentWhitespace(true);

有个地方需要特殊处理,如果解析的是一个流的话,即parse(inputStream)
并且在我们的XML文件中使用的是DTD文件的相对路径,
则需要提供一个实体解析器,用于指定DTD文件。


      

// 实体解析器
public class MyEntityResolver implements EntityResolver {
    @Override
    public InputSource resolveEntity(
           String publicId, 
           String systemId) throws SAXException, IOException {
               
       InputStream stream = Thread.currentThread()
                                  .getContextClassLoader()
                                  .getResourceAsStream("mybatis-config.dtd");
       return new InputSource(stream);
    }
}

// 构建Builder时,设置实体解析器
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver(new MyEntityResolver());

Java XPath定位信息

在定位XML文件信息时,使用获取元素,再判断元素是否是目标元素的办法非常痛苦。
Java 为我们提供了好用的XPath类。

创建XPath对象

XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();

编写表达式,调用evaluate方法求值

// Document document = ...;
// 获取dataSource元素
String expression1 = "/configuration/environments/environment/dataSource";
Node node = (Node) xPath.evaluate(
                    expression1, 
                    document, 
                    XPathConstants.NODE);

// 也可以在当前已获得的节点下开始查找, 获取dateSource的type属性
String type = xPath.evaluate("@type", node);

// 获取mappers下的第一个mapper子元素的resource属性,注意!索引是从1开始的
String expression2 = "/configuration/mappers/mapper[1]/@resource", document);
String resource = xPath.evaluate(
                expression2, 
                document);               

Mybatis 解析XML

XPathParser
在mybatis中,解析XML使用了XPathParser类,这个类是mybatis自定义的,
类中持有一个Document对象,是我们的XML文件,还有一个XPath对象。
类中提供了定位信息的方法,使用的就是Java提供的XPath类。
XPathParser解析出的元素用一个XNode对象存储。

public class XPathParser {

    private Document document;
    private boolean validation;
    private EntityResolver entityResolver;
    private Properties variables;
    private XPath xpath;
    //...
    
    public XNode evalNode(String expression) {
        return evalNode(document, expression);
    }
    
    public XNode evalNode(Object root, String expression) {
        Node node = (Node) evaluate(expression, root, XPathConstants.NODE);
        if (node == null) {
            return null;
        }
        return new XNode(this, node, variables);
    }

    private Object evaluate(String expression, Object root, QName returnType) {
        try {
            return xpath.evaluate(expression, root, returnType);
        } catch (Exception e) {
            throw new BuilderException("Error evaluating XPath.  Cause: " + e, e);
        }
    }            
    //...
}   

XNode
mybatis将Node类进一步封装,用XNode表示。
当构造XNode对象时,会自动解析出元素的元素名、元素的属性等。
此外XNode中提供了获取子元素、获取父元素等行为,由于持有XPathParser对象,
XNode中还提供了定位信息的方法。

public class XNode {

    private Node node;
    private String name;
    private String body;
    private Properties attributes;
    private Properties variables;
    private XPathParser xpathParser;
    
    public XNode(XPathParser xpathParser, Node node, Properties variables) {
        this.xpathParser = xpathParser;
        this.node = node;
        this.name = node.getNodeName();
        this.variables = variables;
        this.attributes = parseAttributes(node);
        this.body = parseBody(node);
    }
    
    public XNode evalNode(String expression) {
        return xpathParser.evalNode(node, expression);
    }
    ...
}

mybatis中,获取根元素只需这样写
XNode root = xPathParser.evalNode("/configuration");
之后获取configuration元素下的mappers是这样写
root.evalNode("mappers")

DTD
mybatis的XML文件使用了DTD,使用解析流的形式解析XML时,
mybatis也提供了实体解析器XMLMapperEntityResolver,
mybatis的DTD文件路径是/org/apache/ibatis/builder/xml/mybatis-3-config.dtd

结语

了解Java提供的解析XML类,再去看各大框架如何解析XML就很容易了。
从这些框架中学习到如何封装好解析的行为,让我们使用的过程中,
不必花费太多功夫去获取XML文档信息,而是直接使用信息。这也是非常大的收获呀。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/76842.html

相关文章

  • JavaXML解析

    摘要:本篇讲在中的解析,最后会简单地讲在解析时的做法。解析器通过解析校验的文件,可以知道哪些元素没有文本节点的子元素,因此可以帮我们剔除空白字符。类将类进一步封装,用表示。当构造对象时,会自动解析出元素的元素名元素的属性等。 许多的Java框架都支持用户自己配置,其中很常见的就是使用XML文件进行配置。本篇讲XML在Java中的解析,最后会简单地讲Mybatis在解析XML时的做法。 XML...

    cheng10 评论0 收藏0
  • Java9模块化学习笔记一快速入门

    摘要:如果你想查看运行时模块的加载过程输出结果表示为模块,由于我限制了不再往下输出了,而我们模块又没有别的额外依赖,所以仅有这行输出。 jdk9模块快速入门 列出自带模块:java --list-modulesmac多版本jdk共存:http://adolphor.com/blog/2016...模块规则示意图:showImg(https://segmentfault.com/img/bVb...

    cjie 评论0 收藏0
  • 【Dubbo源码阅读系列】 Dubbo XML 配置加载

    摘要:在介绍自定义标签解析前,先放一张图帮助大家理解以下是如何从文件中解析并加载的。自定义标签比如的值为根据获取到的,获取对应的对象。关于和加载先后顺序的问题最后再集合一个小例子总结下吧当我们先解析了元素时,我们会遍历所有已经注册注册表中。 今天我们来谈谈 Dubbo XML 配置相关内容。关于这部分内容我打算分为以下几个部分进行介绍: Dubbo XML Spring 自定义 XML 标...

    wangshijun 评论0 收藏0
  • #私藏项目实操分享# 使用 JavaScript 上传 PDF 和 Excel 等二进制文件到 AB

    摘要:这是年的第篇文章,也是汪子熙公众号总共第篇原创文章。使用通过格式发送和文件到服务器关于格式的详细说明,参考开发社区和的文档我在前文例子的基础上稍作修改在里使用两个类型为的标签,分别上传和文件用来测试的本地文件,大小为字节。 这是 Jerry 2021 年的第 71 篇文章,也是汪子熙公众号总共第 348 篇原创文章。 Jerry 之前发布过一篇文章 不使用任何框架,手写纯 Jav...

    peixn 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<