SAX解析器:忽略特殊字符

我正在使用Xerces来解析我的xml文档。 问题是xml转义了像’ ’这样的字符 在characters()方法中显示为非转义的。 我需要按原样在characters()方法中获取转义字符。

谢谢。

UPD:试图在我的DefaultHandler的后代中覆盖resolveEntity方法。 从调试中可以看出它被设置为xml阅读器的实体解析器,但是没有调用来自重写方法的代码。

我认为你的解决方案并不算太糟糕:几行代码可以完全按照你的意愿行事。 问题是ContentHandler接口不提供startEntityendEntity方法,因此您必须编写一个与ContentHandler结合使用的LexicalHandler 。 通常,使用XMLFilter更优雅,但您必须使用实体,因此您仍应编写LexicalHandler 。 请看这里介绍SAXfilter的使用。

我想向您展示一种与您非常相似的方法,它允许您将输出操作(或其他内容)的过滤操作(包装和输出)分开。 我已经编写了基于XMLFilterImpl ,它也实现了LexicalHandler接口。 此filter仅包含与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 ,根据filter代码接收实体:

 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 = "title&"; 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); } 

但仍需要优雅的解决方案。

还有一个可能是: org.apache.commons.lang.StringEscapeUtils类的escapeXml方法。

在你的characters(char[] ch, int start, int length)尝试这个代码characters(char[] ch, int start, int length)方法:

 String data=new String(ch, start, length); String escapedData=org.apache.commons.lang.StringEscapeUtils.escapeXml(data); 

你可以在这里下载jar。