我正在使用Xerces来解析我的xml文档。问题是xml转义了像'& nbsp;'这样的字符在characters()方法中显示为非转义的。我需要在characters()方法中获取转义字符。
感谢。
UPD:试图在我的DefaultHandler的后代中覆盖resolveEntity方法。从调试中可以看出它被设置为xml阅读器的实体解析器,但是没有调用来自重写方法的代码。
答案 0 :(得分:7)
我认为您的解决方案并不算太糟糕:只需几行代码即可完成您想要的工作。
问题是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。
答案 1 :(得分:5)
如果您提供LexicalHandler作为SAX解析器的回调,它将使用startEntity()和endEntity()回调通知您每个实体引用的开始和结束。
(请注意,http://download.oracle.com/javase/1.5.0/docs/api/org/xml/sax/ext/LexicalHandler.html处的JavaDoc会在正确的术语为“实体引用”时与“实体”进行对话。)
另请注意,无法让SAX解析器告诉您有关ሴ
等数字字符引用的信息。应用程序应该以与原始角色完全相同的方式处理它们,所以你真的不应该对它们感兴趣。
答案 2 :(得分:1)
临时解决方案:
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);
}
但仍然需要优雅的解决方案。
答案 3 :(得分:1)
还有一个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。