DOM4J解析XML之忽略转义字符
项⽬经验,如需转载,请注明作者:Yuloran ()
背景
项⽬开发需要⼿动合⼊⼏⼗种语⾔的翻译到 l 中,这是⼀件⾮常痛苦的事情:Copy、Paste,Copy、Paste,Copy、⼈都快疯了!被逼⽆奈写了个⾃动替换翻译的⼯具。原理很简单:解析 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;
l.sax.InputSource;
l.sax.SAXException;
l.parsers.DocumentBuilder;
l.parsers.DocumentBuilderFactory;
l.parsers.ParserConfigurationException;
l.transform.OutputKeys;
l.transform.Transformer;
l.transform.TransformerException;
l.transform.TransformerFactory;
l.transform.dom.DOMSource;
l.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 = wInstance();
DocumentBuilder documentBuilder = wDocumentBuilder();
Document document = documentBuilder.parse(new InputSource(new InputStreamReader(new FileInputStream("l"), "UTF-8")));
// 2. 遍历
NodeList strings = ElementsByTagName("string");
for (int i = 0; i < Length(); i++) {
Node item = strings.item(i);
System.out.print(String.format("Element:[tag:%s, content:%s] ", NodeName(), TextContent()));
NamedNodeMap attributes = Attributes();
for (int j = 0; j < Length(); j++) {
Node attr = attributes.item(j);
System.out.println(String.format("Attr:[key:%s, value:%s]", NodeName(), NodeValue()));
}
}
// 3. 保存
Transformer transformer = wInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
}
}
复制代码
解析⽇志:
l:
DOM 解析保存 XML ⽂件的问题:
XML ⽂档声明中⾃动添加 standalone="no",可以通过 document.setXmlStandalone(true); 去除,但是这样的话,缩进就会失效!
⽂件换⾏符⾃动更换为操作系统所在的换⾏符!
所以,我不⽤ DOM,⽽是⽤ DOM4J。⽤了 DOM4J 这些问题都将成为浮云!
DOM4J 解析
太简单啦!直接阅读即可!我从未见过如此简洁明了的 API ⽂档!
DOM4J jar 包及依赖下载:
注意看截图:
如果⼯程中 dom4j 是 maven 依赖,就不需要⼿动下载 jaxen.jar。如果是 jar 依赖,还需要下载 jaxen.jar,否则编译时会不到类。DOM4J 使⽤⽰例
package com.yuloran;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
l.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 = ad(new InputSource(new InputStreamReader(new FileInputStream("l"), "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] ", Name(), Text()));使用dom4j解析xml文件
System.out.println(String.format("Attr:[name@%s]", node.valueOf("@name")));
}
// 3.保存
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("l"), "UTF-8");
XMLWriter xmlWriter = new XMLWriter(writer);
// 忽略 Element 对象中的转义字符
xmlWriter.setEscapeText(false);
xmlWriter.write(document);
xmlWriter.close();
}
}
复制代码
l:
怎么样?看看这输出,⼀点⽑病没有!
忽略转义字符
其实这是 SAX(Simple Application Interface For Xml) 解析的问题,SAX 解析 XML 时,会⾃动将元素⽂本中的转义字符转义,导致最后将 Document 对象保存为⽂件时,⽆法将原转义字符写回:
原⽂件:
DOM4J 解析再写回:
所以,我们需要实现⼀个过滤器,每当 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("l"), "UTF-8");
XMLWriter xmlWriter = new XMLWriter(writer);
xmlWriter.setEscapeText(false);
xmlWriter.write(document);
xmlWriter.close();
复制代码
测试结果:
⽇志:
l:
其它的转义字符也是同样的处理⽅法。可以将要忽略的转义字符放到配置⽂件中,做⼯具的时候从配置中读取要忽略的转义字符,这样更灵活。
总结
本⽂只写了最终的解决⽅案,实际上探索这个解决⽅案的过程还是⽐较复杂的。需求⼩众,没什么资料,只能看源码,猜接⼝,反正我是不相信这样的解析框架是没有暴露⽤户⾃⾏处理字符串的接⼝的。果然还是可以通过 characters() ⽅法,只是 SAXReader 没有暴露ContentHandler 接⼝,内部封装成了 SAXContentHandler,characters() ⽅法则暴露到了 XMLFilter 接⼝中,哈,⼀番好。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论