美文网首页
(3) Dom(Document Object Model)解析

(3) Dom(Document Object Model)解析

作者: Mrsunup | 来源:发表于2018-10-24 20:56 被阅读0次

    1.DOM的API说明

    image.png

    dom原名为Document Object Model ,文档对象模型

    可以用 javax.xml.parsers.DocumentBuilderFactory得到DocumentBuilder 实例,然后根据DocumentBuilder的newDocument() 得到Document 实例,也可以DocumentBuilder的parse方法指定解析xml文件得到Document 实例,document 实例的看起来就像是一颗dom节点树

    一个dom实例就像一个标准的树结构,每一个节点代表着来自于xml的结构,最常用的节点为text节点和element 节点,使用dom可以创建,移除和改变节点的内容,遍历节点的层级

    dom的特点:api使用比sax灵活,可以从dom结构灵活处理dom节点,但是dom的模型是基于内存的,如果有对内存要求比较高的程序可以使用sax这个方式解析,对于复杂的xml一般建议使用dom解析

    2.dom的命名空间元素验证以及异常处理

    下面的例子,注重理解如何验证xml的命名空间以及xml中的元素验证
    然后理解dom的解析的异常处理

    • 创建dom解析器
     //得到DocumentBuilderFactory工厂实例
    DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
    //得到DocumentBuilder 对象
    DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
      //解析文档
     Document document = documentBuilder.parse(xmlFile);
    
    • xml文件命名空间的验证
      第一是否设置要进行验证,setValidating设置为true,表示要验证, 第二个需要给builderFactory设置属性,一个是JAXP_SCHEMA_LANGUAGE ,一个是W3C_XML_SCHEMA 表示是否符合xml语言规范
        // "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
        static final String JAXP_SCHEMA_LANGUAGE = JAXPConstants.JAXP_SCHEMA_LANGUAGE;
    
        //"http://www.w3.org/2001/XMLSchema";
        static final String W3C_XML_SCHEMA =JAXPConstants.W3C_XML_SCHEMA;
    
       //设置解析器在解析文档的时候校验文档
            builderFactory.setValidating(true);
            //让解析器支持命名空间
            builderFactory.setNamespaceAware(true);
            //通过指定factory的属性,确定使用Schema进行校验
            builderFactory. setAttribute(JAXP_SCHEMA_LANGUAGE,W3C_XML_SCHEMA);
    
    • xml文件元素的验证
      一般来说,写xml的时候需要用到xsd和dtd文件的约束,于是给DocumentBuilderFactory设置具体的属性,来表明具体的xsd和dtd文件在哪,引导程序进行验证就行
        //     "http://java.sun.com/xml/jaxp/properties/schemaSource";
        static final String JAXP_SCHEMA_SOURCE =JAXPConstants.JAXP_SCHEMA_SOURCE;
       //设置对该文件进行元素验证,不合法的元素会报错
            //方式1 
            String  schemaFileName ="D:\\Eclipse2018Data\\personProject\\jdk\\java-jaxp\\src\\main\\java\\com\\java\\jaxp\\dom\\spring-beans.xsd";
           //方式2
            File schemaFile = new File(schemaFileName);
            //方式3
            String[] schemaFileNames = new String[]{schemaFileName};
            //setAttribute的value可以是在看字符串,也可以是字符串数组,表示有多个文件约束,也是可以文件的形式
            builderFactory.setAttribute(JAXP_SCHEMA_SOURCE, schemaFileName);
    

    还有第二种方式,需要是实现一个EntityResolver接口来进行转换xsd和dtd文件的位置(详细的例子会在下面全部给出)

      public interface EntityResolver {
       public abstract InputSource resolveEntity (String publicId,
                                                   String systemId)
            throws SAXException, IOException;
    
    }
    
    • 解析异常处理
      一般需要给DocumentBuilder对象设置错误的解析器
     //添加ErrorHandler,将解析的异常手动抛出
            documentBuilder.setErrorHandler(new ErrorHandler() {
                @Override
                public void warning(SAXParseException exception) throws SAXException {
                    System.out.println("warning");
                    throw  exception;
                }
    
                private String getParseExceptionInfo(SAXParseException spe) {
                    String systemId = spe.getSystemId();
                    if (systemId == null) {
                        systemId = "null";
                    }
    
                    String info = "URI=" + systemId + " Line=" + spe.getLineNumber() +
                            ": " + spe.getMessage();
                    return info;
                }
    
                @Override
                public void error(SAXParseException exception) throws SAXException {
                    String message = "Error: " + getParseExceptionInfo(exception);
                    System.out.println(message);
                    throw new SAXException(message);
            }
    
                @Override
                public void fatalError(SAXParseException exception) throws SAXException {
                    System.out.println("fatal");
                    throw  exception;
                }
            });
    

    完整的代码如下:
    代码实现了xml的命名空间的验证以及xml元素的验证,xml为具有spring-beans的文件,需要准备spring-beans的dtd文件

    • 验证的xml文件
    <?xml version="1.0" encoding="utf-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
    
        <bean class="com.java.jaxp.dom.ValidateXmlTest" id="validateXmlTest" >
            <property name="sun" value="kang"></property>
            <property name="list">
                <props>
                    <prop key="23">234</prop>
                </props>
            </property>
        </bean>
    </beans>
    
    • spring-beans.xsd文件
    从spring的中jar包取一个出来,这里我就不展示了
    
    • 主程序
    /**
     * @Project: jdk
     * @description:  dom的验证xml命名空间
     * @author: sunkang
     * @create: 2018-10-18 12:57
     * @ModificationHistory who      when       What
     **/
    public class ValidateXmlTest {
    
        // "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
        static final String JAXP_SCHEMA_LANGUAGE = JAXPConstants.JAXP_SCHEMA_LANGUAGE;
    
        //"http://www.w3.org/2001/XMLSchema";
        static final String W3C_XML_SCHEMA =JAXPConstants.W3C_XML_SCHEMA;
    
        //     "http://java.sun.com/xml/jaxp/properties/schemaSource";
        static final String JAXP_SCHEMA_SOURCE =JAXPConstants.JAXP_SCHEMA_SOURCE;
    
        public static void main(String[] args) throws Exception{
            //得到DocumentBuilderFactory工厂实例
            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
            //解析文档
            //设置解析器在解析文档的时候校验文档
            builderFactory.setValidating(true);
            //让解析器支持命名空间
            builderFactory.setNamespaceAware(true);
            //通过指定factory的属性,确定使用Schema进行校验
            builderFactory. setAttribute(JAXP_SCHEMA_LANGUAGE,W3C_XML_SCHEMA);
    
            //设置对该文件进行元素验证,不合法的元素会报错
            //方式1
            String  schemaFileName ="D:\\Eclipse2018Data\\personProject\\jdk\\java-jaxp\\src\\main\\java\\com\\java\\jaxp\\dom\\spring-beans.xsd";
           //方式2
            File schemaFile = new File(schemaFileName);
            //方式3
            String[] schemaFileNames = new String[]{schemaFileName};
            //setAttribute的value可以是在看字符串,也可以是字符串数组,表示有多个文件约束,也是可以文件的形式
       //     builderFactory.setAttribute(JAXP_SCHEMA_SOURCE, schemaFileName);
    
            //忽略空白
            boolean ignoreWhitespace = false;
            boolean ignoreComments = false;
            boolean putCDATAIntoText = false;
            boolean createEntityRefs = false;
            builderFactory.setIgnoringComments(ignoreComments);
            builderFactory.setIgnoringElementContentWhitespace(ignoreWhitespace);
            builderFactory.setCoalescing(putCDATAIntoText);
            builderFactory.setExpandEntityReferences(!createEntityRefs);
            DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
            //解析dtd文件
          documentBuilder.setEntityResolver(new SpringBeansEntityResolver());
            //添加ErrorHandler,将解析的异常手动抛出
            documentBuilder.setErrorHandler(new ErrorHandler() {
                @Override
                public void warning(SAXParseException exception) throws SAXException {
                    System.out.println("warning");
                    throw  exception;
                }
    
                private String getParseExceptionInfo(SAXParseException spe) {
                    String systemId = spe.getSystemId();
                    if (systemId == null) {
                        systemId = "null";
                    }
    
                    String info = "URI=" + systemId + " Line=" + spe.getLineNumber() +
                            ": " + spe.getMessage();
                    return info;
                }
    
                @Override
                public void error(SAXParseException exception) throws SAXException {
                    String message = "Error: " + getParseExceptionInfo(exception);
                    System.out.println(message);
                    throw new SAXException(message);
            }
    
                @Override
                public void fatalError(SAXParseException exception) throws SAXException {
                    System.out.println("fatal");
                    throw  exception;
                }
            });
    
            File xmlFile = new File("D:\\Eclipse2018Data\\personProject\\jdk\\java-jaxp\\src\\main\\java\\com\\java\\jaxp\\dom\\applicationContext.xml");
            //解析文档
            Document document = documentBuilder.parse(xmlFile);
        }
    
    • 第二种xml元素验证方式(主要参考了mybatis 中的org.apache.ibatis.builder.xml.XMLMapperEntityResolver的实现方式)
    /**
     * @Project: jdk
     * @description:  验证xml元素的实体解析器
     * @author: sunkang
     * @create: 2018-10-18 14:01
     * @ModificationHistory who      when       What
     **/
    public class SpringBeansEntityResolver implements EntityResolver {
    
        private static final String SPRING_BEANS_SYSTEM = "spring-beans-3.2.xsd";
    
        @Override
        public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
            System.out.println("publicId : "+ publicId);
            System.out.println("systemId : "+systemId );
            //如果这个xsd的资源没有设置绝对路劲之前会是: systemId :http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    
            if (systemId != null) {
                String lowerCaseSystemId = systemId.toLowerCase(Locale.ENGLISH);
                if (lowerCaseSystemId.contains(SPRING_BEANS_SYSTEM)) {
                    return this.getInputSource("org/springframework/beans/factory/xml/spring-beans.xsd", publicId, systemId);
                }
            }
            return null;
        }
    
    
        private InputSource getInputSource(String path, String publicId, String systemId) {
            InputSource source = null;
            if (path != null) {
                try {
                    InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
                    source = new InputSource(in);
                    source.setPublicId(publicId);
                    source.setSystemId(systemId);
                } catch (Exception var6) {
                    ;
                }
            }
    
            return source;
        }
    }
    

    3.dom的元素解析

    例子如下,给出beans.xml文件,根据里面的文件内容,把里边的内容平凑成json的形式,然后输出出来

    • beans.xml的内容如下:
    <beans>
        <bean id="bean1" class ="com.java.jaxp.dom">
              <property name="username">sunkang</property>
        </bean>
        <bean id="bean2" class ="com.java.jaxp.dom">
            <property name="name">sunkang</property>
        </bean>
    </beans>
    
    • 解析程序如下:
    /**
     * @Project: jdk
     * @description:
     * @author: sunkang
     * @create: 2018-10-18 15:18
     * @ModificationHistory who      when       What
     **/
    public class DomParserDemo {
    
        public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    
            String fileName = "D:\\Eclipse2018Data\\personProject\\jdk\\java-jaxp\\src\\main\\java\\com\\java\\jaxp\\dom\\Beans.xml";
            File file = new File(fileName);
    
            Document document = documentBuilder.parse(file);
            StringBuffer sbf = new StringBuffer();
            //解析beans的元素
            populateBeans(document, sbf);
            System.out.println(sbf.toString());
        }
    
        public static void populateBeans(Document document, StringBuffer sbf) {
            Element root = document.getDocumentElement();
            String beans = root.getTagName();
            populateBean(document, sbf);
            sbf.append("}");
        }
    
    
        public static void populateBean(Document document, StringBuffer sbf) {
            NodeList nodeList = document.getElementsByTagName("bean");
            sbf.append("{bean:");
            for (int i = 0; i < nodeList.getLength(); i++) {
                Element beanElement = (Element) nodeList.item(i);
                String id = beanElement.getAttribute("id");
                String clazz = beanElement.getAttribute("class");
                sbf.append("{id :" + id + ",");
                sbf.append("clazz :" + id + ",");
    
                //解析property属性
                populateProperty(beanElement, sbf);
                if (i != nodeList.getLength() - 1) {
                    sbf.append("},");
                } else {
                    sbf.append("}");
                }
            }
            sbf.append("}");
    
        }
    
        public static void populateProperty(Element beanElement, StringBuffer sbf) {
            NodeList propertyList = beanElement.getElementsByTagName("property");
            for (int j = 0; j < propertyList.getLength(); j++) {
                Node node = propertyList.item(j);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    Element property = (Element) node;
                    String name = property.getAttribute("name");
                    //获取property的标签的值,下面的这个方法是可以的
                    //String value = property.getFirstChild().getNodeValue();
                    String value = property.getTextContent();
                    sbf.append("property :{name:" + name+ ",");
                    sbf.append("value:" + value + "}");
                }
            }
        }
    
    }
    
    • 输出结果如下
    {bean:{id :bean1,clazz :bean1,property :{name:username,value:sunkang}},{id :bean2,clazz :bean2,property :{name:name,value:sunkang}}}}
    

    相关文章

      网友评论

          本文标题:(3) Dom(Document Object Model)解析

          本文链接:https://www.haomeiwen.com/subject/nsoxtqtx.html