DOM4J 解析 XML 之忽略转义字符

栏目: 编程语言 · XML · 发布时间: 7年前

内容简介:项目开发需要手动合入几十种语言的翻译到 string.xml 中,这是一件非常痛苦的事情:Copy、Paste,Copy、Paste,Copy、Paste... 人都快疯了!被逼无奈写了个自动替换翻译的工具。原理很简单:解析 Excel中的翻译,替换到 Xml 中。Excel 解析用 jxl.jar,Xml 解析与修改用 DOM,一顿操作,一天就写完了!正高兴呢,赶紧使用 git diff 查看修改对比,一看坏事了:“坑爹呢!一点也不完美啊!原字符串中的转义字符全被转义了好嘛!难道还要手动还回去嘛!像我这样

项目开发需要手动合入几十种语言的翻译到 string.xml 中,这是一件非常痛苦的事情:Copy、Paste,Copy、Paste,Copy、Paste... 人都快疯了!被逼无奈写了个自动替换翻译的工具。原理很简单:解析 Excel中的翻译,替换到 Xml 中。Excel 解析用 jxl.jar,Xml 解析与修改用 DOM,一顿操作,一天就写完了!正高兴呢,赶紧使用 git diff 查看修改对比,一看坏事了:“坑爹呢!一点也不完美啊!原字符串中的转义字符全被转义了好嘛!难道还要手动还回去嘛!像我这样优(懒)秀(惰)的人根本无法容忍好嘛!” 所以,本文记录如何使用 DOM4J(上面不是说用 DOM 解析吗?这里怎么又成 DOM4J 了?忽悠谁呢!) 解析 XML 并让其忽略转义字符。

为什么不用 DOM

谁说我没用 DOM,我一上来就用的 DOM 好嘛!毕竟 JDK 自带的啊!但是用了后,用户体验贼差好嘛!稍微贴下使用方法:

package com.yuloran;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

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

public class Main {

    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException, TransformerException {

        // 1. 解析
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = factory.newDocumentBuilder();
        Document document = documentBuilder.parse(new InputSource(new InputStreamReader(new FileInputStream("strings.xml"), "UTF-8")));

        // 2. 遍历
        NodeList strings = document.getElementsByTagName("string");
        for (int i = 0; i < strings.getLength(); i++) {
            Node item = strings.item(i);
            System.out.print(String.format("Element:[tag:%s, content:%s] ", item.getNodeName(), item.getTextContent()));
            NamedNodeMap attributes = item.getAttributes();
            for (int j = 0; j < attributes.getLength(); j++) {
                Node attr = attributes.item(j);
                System.out.println(String.format("Attr:[key:%s, value:%s]", attr.getNodeName(), attr.getNodeValue()));
            }
        }

        // 3. 保存
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.transform(new DOMSource(document), new StreamResult("strings_copy.xml"));
    }

}
复制代码

strings.xml:

DOM4J 解析 XML 之忽略转义字符

解析日志:

DOM4J 解析 XML 之忽略转义字符

strings_copy.xml:

DOM4J 解析 XML 之忽略转义字符

DOM 解析保存 XML 文件的问题:

document.setXmlStandalone(true);

所以,我不用 DOM,而是用 DOM4J。用了 DOM4J 这些问题都将成为浮云!

DOM4J 解析

太简单啦!直接阅读官方指南即可!我从未见过如此简洁明了的 API 文档!

DOM4J jar 包及依赖下载:

DOM4J 使用示例

package com.yuloran;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;

import java.io.*;
import java.util.List;

public class Main {

    public static void main(String[] args) throws DocumentException, IOException {
        // 1. 解析
        SAXReader reader = new SAXReader();
        Document document = reader.read(new InputSource(new InputStreamReader(new FileInputStream("strings.xml"), "UTF-8")));

        // 2. 遍历
        List<Node> list = document.selectNodes("/resources/string[@name]");
        for (Node node : list) {
            System.out.print(String.format("Element:[tag:%s, content:%s] ", node.getName(), node.getText()));
            System.out.println(String.format("Attr:[name@%s]", node.valueOf("@name")));
        }

        // 3.保存
        OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("strings_dom4j.xml"), "UTF-8");
        XMLWriter xmlWriter = new XMLWriter(writer);
        // 忽略 Element 对象中的转义字符
        xmlWriter.setEscapeText(false);
        xmlWriter.write(document);
        xmlWriter.close();
    }

}
复制代码

strings_dom4j.xml:

DOM4J 解析 XML 之忽略转义字符

怎么样?看看这输出,一点毛病没有!

忽略转义字符

其实这是 SAX(Simple Application Interface For Xml) 解析的问题,SAX 解析 XML 时,会自动将元素文本中的转义字符转义,导致最后将 Document 对象保存为文件时,无法将原转义字符写回:

原文件:

DOM4J 解析 XML 之忽略转义字符

DOM4J 解析再写回:

DOM4J 解析 XML 之忽略转义字符

所以,我们需要实现一个过滤器,每当 SAX 解析一个转义字符,我们就将其原样写回:

reader.setXMLFilter(new XMLFilterImpl() {
            @Override
            public void characters(char[] ch, int start, int length) throws SAXException {
                String text = new String(ch, start, length);
                System.out.println("text is: " + text);

                if (length == 1) {
                    if ((int) ch[0] == 160) {
                        char[] escape = " ".toCharArray();
                        super.characters(escape, 0, escape.length);
                        return;
                    }
                }

                super.characters(ch, start, length);
            }
        });
复制代码

再配合 xmlWriter.setEscapeText(false); 即可原样输出原 Xml 文件中的转义字符:

// 3.保存
        OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("strings_dom4j.xml"), "UTF-8");
        XMLWriter xmlWriter = new XMLWriter(writer);
        xmlWriter.setEscapeText(false);
        xmlWriter.write(document);
        xmlWriter.close();
复制代码

测试结果:

DOM4J 解析 XML 之忽略转义字符

日志:

DOM4J 解析 XML 之忽略转义字符

strings_dom4j.xml:

DOM4J 解析 XML 之忽略转义字符

其它的转义字符也是同样的处理方法。可以将要忽略的转义字符放到配置文件中,做 工具 的时候从配置中读取要忽略的转义字符,这样更灵活。

总结

本文只写了最终的解决方案,实际上探索这个解决方案的过程还是比较复杂的。需求小众,没什么资料,只能看源码,猜接口,反正我是不相信这样的解析框架是没有暴露用户自行处理字符串的接口的。果然还是可以通过 characters() 方法,只是 SAXReader 没有暴露 ContentHandler 接口,内部封装成了 SAXContentHandler,characters() 方法则暴露到了 XMLFilter 接口中,哈,一番好找。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Convergence Culture

Convergence Culture

Henry Jenkins / NYU Press / 2006-08-01 / USD 30.00

"Convergence Culture" maps a new territory: where old and new media intersect, where grassroots and corporate media collide, where the power of the media producer, and the power of the consumer intera......一起来看看 《Convergence Culture》 这本书的介绍吧!

html转js在线工具
html转js在线工具

html转js在线工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具