我正在使用 Xerces 来解析我的 XML 文档。问题是 XML 转义字符(如方法 
中characters()
的非转义字符)。我需要在characters()
方法中按原样获取转义字符。
谢谢。
UPD:试图覆盖resolveEntity()
我DefaultHandler
的后代中的方法。从调试中可以看出,它被设置为 XML 阅读器的实体解析器,但未调用来自重写方法的代码。
我认为您的解决方案还不错:几行代码就可以完全按照您的意愿行事。问题是startEntity
和endEntity
方法不是由ContentHandler
接口提供的,所以你必须编写一个LexicalHandler
与你的ContentHandler
. 通常,使用 anXMLFilter
更优雅,但你必须使用实体,所以你仍然应该写一个LexicalHandler
. 在这里查看有关 SAX 过滤器使用的介绍。
我想向您展示一种与您的非常相似的方法,它允许您将过滤操作(&
例如包装 & to)与输出操作(或其他操作)分开。我已经写了我自己XMLFilter
的基于XMLFilterImpl
它也实现了LexicalHandler
接口。此过滤器仅包含与实体转义/取消转义相关的代码。
public class XMLFilterEntityImpl extends XMLFilterImpl implements
LexicalHandler {
private String currentEntity = null;
public XMLFilterEntityImpl(XMLReader reader)
throws SAXNotRecognizedException, SAXNotSupportedException {
super(reader);
setProperty("http://xml.org/sax/properties/lexical-handler", this);
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if (currentEntity == null) {
super.characters(ch, start, length);
return;
}
String entity = "&" + currentEntity + ";";
super.characters(entity.toCharArray(), 0, entity.length());
currentEntity = null;
}
@Override
public void startEntity(String name) throws SAXException {
currentEntity = name;
}
@Override
public void endEntity(String name) throws SAXException {
}
@Override
public void startDTD(String name, String publicId, String systemId)
throws SAXException {
}
@Override
public void endDTD() throws SAXException {
}
@Override
public void startCDATA() throws SAXException {
}
@Override
public void endCDATA() throws SAXException {
}
@Override
public void comment(char[] ch, int start, int length) throws SAXException {
}
}
这是我的主要内容,它根据过滤器代码接收实体DefaultHandler
:ContentHandler
public static void main(String[] args) throws ParserConfigurationException,
SAXException, IOException {
DefaultHandler defaultHandler = new DefaultHandler() {
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
//This method receives the entity as is
System.out.println(new String(ch, start, length));
}
};
XMLFilter xmlFilter = new XMLFilterEntityImpl(XMLReaderFactory.createXMLReader());
xmlFilter.setContentHandler(defaultHandler);
String xml = "<html><head><title>title</title></head><body>&</body></html>";
xmlFilter.parse(new InputSource(new StringReader(xml)));
}
这是我的输出:
title
&
可能您不喜欢它,无论如何这是一个替代解决方案。
对不起,但SaxParser
我认为你没有更优雅的方式。
您还应该考虑切换到StaxParser
XMLInputFactory.IS_REPLACING_ENTITY_REFERENCE
:设置为 false可以很容易地做您想做的事情。如果你喜欢这个解决方案,你应该看看这里。
如果您提供 LexicalHandler 作为 SAX 解析器的回调,它将使用 startEntity() 和 endEntity() 回调通知您每个实体引用的开始和结束。
(请注意,当正确的术语是“实体引用”时,http: //download.oracle.com/javase/1.5.0/docs/api/org/xml/sax/ext/LexicalHandler.html上的 JavaDoc 谈到了“实体” ”)。
另请注意,没有办法让 SAX 解析器告诉您有关数字字符引用的信息,例如ሴ
. 应用程序应该以与原始角色完全相同的方式对待这些,所以你真的不应该对它们感兴趣。
临时解决方案:
public void startEntity(String name) throws SAXException {
inEntity = true;
entityName = name;
}
public void characters(char[] ch, int start, int length) throws SAXException {
String data;
if (inEntity) {
inEntity = false;
data = "&" + entityName + ";";
} else {
data = new String(ch, start, length);
}
//TODO do something instead of System.out
System.out.println(data);
}
但仍然需要优雅的解决方案。
还有一个可能:类escapeXml
的方法 org.apache.commons.lang.StringEscapeUtils
。
characters(char[] ch, int start, int length)
在您的方法中尝试此代码:
String data=new String(ch, start, length);
String escapedData=org.apache.commons.lang.StringEscapeUtils.escapeXml(data);
你可以在这里下载 jar 。