XML(五):逐步分析DOM解析XML之增、保存、缩进

XML文件源码如下:



    
        
    
    

        
        
    

一、增

要在PhoneInfo的节点上添加品牌节点,需要先找到PhoneInfo节点。然后在此DOM树上创建一个新的Brand品牌节点,设置它的属性name为“MOTO”。然后根据它在DOM树的位置,把它添加为PhoneInfo的子节点。这样,此DOM树就有了新的结构。最后把这个DOM树结构保存到XML文件就可以了。
综上,实现步骤如下:
1、为XML文档构造DOM树
2、创建新节点,并设置name属性
3、把节点加到其所属父节点上
4、保存XML文档
其实整体的思路就是我先在DOM树外创建元素节点,然后再把元素节点添加到DOM树中,用到的方法主要是:

createElement(元素类型)  创建一个某种类型的元素
setAttribute(属性,   属性值) 为该元素添加属性
父元素.appendChild(子元素)添加父子关系

代码如下:

// 添加节点信息
    public void addBrand() {
        // 创建Brand节点
        Element brandElement = document.createElement("Brand");
        brandElement.setAttribute("name", "MOTO");
        // 创建Type节点
        Element typeElement = document.createElement("Type");
        typeElement.setAttribute("name", "A1680");
        // 添加父子关系
        brandElement.appendChild(typeElement);
        // 在DOM树外把标签为PhoneInfo的元素拿出来,以方便下一步把新建的节点加进去
        Element phoneElement = (Element)document.getElementsByTagName("PhoneInfo").item(0);
        // 添加父子关系
        phoneElement.appendChild(brandElement);
        // 把新的DOM树保存到XML文件之中
        saveXML();
}

下面这行代码:

 Element phoneElement = (Element)document.getElementsByTagName("PhoneInfo").item(0);

的意思是:通过Document拿到标签名字为PhoneInfo的标签,把该节点强转为Element类型后,然后再把新建的Brand节点加进去。

注:上面这些操作都是在操作内存中的DOM树,操作完毕之后内存中的DOM树变化了,但是XML文件并没有改变。还需要将内存中的DOM树保存到XML文件中。

二、保存

保存XML文件,需要借助转换器:源(最新的DOM树)-->目的地(手机信息.xml),借助输出流来实现。
代码如下:

// 保存XML文件
    public void saveXML() {
        // 转换器工厂
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        try {
            // 转换器
            Transformer transformer = transformerFactory.newTransformer();
        
            DOMSource domSource = new DOMSource(document);
            StreamResult result = new StreamResult(new FileOutputStream("手机信息.xml"));
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            // 转换器的方法,对应于解析器的解析方法(parse())
            transformer.transform(domSource, result);
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        }       
   }

分析:
1、保存XML文件需要借助转换器,这个跟解析XML文件时用的解析器相对应。如下:
转换器工厂对应解析器工厂TransformerFactory transformerFactory = TransformerFactory.newInstance();对应DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();;转换器对应解析器Transformer transformer = transformerFactory.newTransformer();对应DocumentBuilder db = factory.newDocumentBuilder();;转换方法对应解析方法:parse()对应transform()。两个方法需要的参数不一样,返回的结果也不一样。
parse()方法需要的参数是一个XML文件,返回结果是一个DOM树。transform()方法需要的参数是(要保存的DOM源和一个Result)(transformer.transform(Source, Result);)。
2、对于transform()方法中的两个参数,Source和Result,在XML文档的保存中分别是DOMSource和StreamResult。DOMSource很简单,就是直接把document作为参数传进去即可:DOMSource domSource = new DOMSource(document);
但是StreamResult构造对象时有三种常用构造方法,参数分别不同:
第一种:StreamResult result = new StreamResult("手机信息.xml");直接把文件传进来作为参数,但是此时需要制定文档编码格式,否则可能在最后的XML文件中出现乱码。指定字符编码格式代码如下:transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
第二种:StreamResult result = new StreamResult(new FileOutputStream("手机信息.xml"));将一个OutputStream类型的数据作为参数传进去。但是此时也需要制定编码格式:transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
第三种:将一个Writer类型的数据作为参数传进去:

    OutputStream out = new FileOutputStream("手机信息.xml");
    StreamResult result = new StreamResult(new OutputStreamWriter(out, "UTF-8"));

此时不需要前两种方法的指定编码格式了,因为OutputStreamWriter()对象在输出是可以直接指定编码格式。
保存之后的XML文件如下:


    
        
        
        
    
     
        
        
        
    

注1:OutputKeys.ENCODING意思是设置输出时候的编码。OutputKeys是输出时候的关键字,里面定义了一些静态方法,可以设置输出时候的一些格式等。

注2:如果出现中文乱码,需要

 StreamResult result = new StreamResult(new OutputStreamWriter(out, "UTF-8"));
 transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");

两句同时写上才有用。

三、设置缩进

从上面保存后的XML文件来看,只是增加在最后一行,没有设置缩进,看着非常别扭。那怎么设置缩进呢?
设置缩进分两步:
第一步:允许缩进

transformerFactory.setAttribute("indent-number", 4);

通过调用转换器工厂的这个方法可以设置缩进的空格数目。
第二步:允许缩进

transformer.setOutputProperty(OutputKeys.INDENT, "YES");

在转换器中把OutputKeys的关键字INDENT相应的值设置为YES,这就表示允许在将内存中的DOM树写进XML文件的时候设置缩进。
加上设置缩进的代码之后,代码如下:

public void saveXML() {
        // 转换器工厂
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        // 设置缩进
        transformerFactory.setAttribute("indent-number", 4);
        try {
            // 转换器
            Transformer transformer = transformerFactory.newTransformer();
            DOMSource domSource = new DOMSource(document);
            OutputStream out = new FileOutputStream("手机信息.xml");
            transformer.setOutputProperty(OutputKeys.INDENT, "YES");
            StreamResult result = new StreamResult(new OutputStreamWriter(out, "UTF-8")); 
            transformer.transform(domSource, result);
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }       
}

最终的XML文件如下:



    
        
        
        
    
    
        
        
        
    

        
    

注:倒数第四行是没有缩进的,但这不是代码的问题,而是MyEclipse底层源码的问题,忽略不计即可。

你可能感兴趣的:(XML(五):逐步分析DOM解析XML之增、保存、缩进)