我正在使用Xerces来解析我的xml文档。问题是xml转义了像' '这样的字符在characters()方法中显示为非转义的。我需要在characters()方法中获取转义字符。
谢谢。
UPD:尝试覆盖我的DefaultHandler后代的resolveEntity方法。从调试中可以看出它被设置为xml阅读器的实体解析器,但是没有调用来自重写方法的代码。
我认为你的解决方案并不是太糟糕:几行代码可以完全按照你的意愿行事。问题是startEntity
和endEntity
方法不是由ContentHandler
接口提供的,所以你必须写一个与你的LexicalHandler
结合使用的ContentHandler
。通常,使用XMLFilter
更优雅,但你必须使用实体,所以你仍然应该写一个LexicalHandler
。看看here介绍SAX滤波器的使用。
我想向您展示一种与您非常相似的方法,它允许您将输出操作(或其他内容)的过滤操作(包装和&
)分开。我写了自己的基于XMLFilter
的XMLFilterImpl
,它也实现了LexicalHandler
界面。此过滤器仅包含与entites escape / unescape相关的代码。
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的情况下,您可以轻松地执行所需操作。如果你喜欢这个解决方案,你应该看看here。
如果您提供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 here。