我从服务器获取任意 XML 并使用此 Java 代码解析它:
String xmlStr; // arbitrary XML input
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
InputSource is = new InputSource(new StringReader(xmlStr));
return builder.parse(is);
}
catch (SAXException | IOException | ParserConfigurationException e) {
LOGGER.error("Failed to parse XML.", e);
}
每隔一段时间,XML 输入包含一些未知的实体引用,如
并因错误而失败,如 org.xml.sax.SAXParseException: The entity "nbsp "被引用,但未声明。
我可以通过预处理原始 xmlStr
并在解析之前翻译所有有问题的实体引用来解决这个问题。这是一个有效的虚拟实现:
protected static String translateEntityReferences(String xml) {
String newXml = xml;
Map<String, String> entityRefs = new HashMap<>();
entityRefs.put(" ", " ");
entityRefs.put("«", "«");
entityRefs.put("»", "»");
// ... and 250 more...
for(Entry<String, String> er : entityRefs.entrySet()) {
newXml = newXml.replace(er.getKey(), er.getValue());
}
return newXml;
}
不过,这确实不尽如人意,因为有are a huge number of entity references我不想将其全部硬编码到我的 Java 类中。
是否有任何简单的方法可以将整个字符实体引用列表传授给 DocumentBuilder?
最佳答案
如果您可以更改代码以使用 StAX 而不是 DOM,简单的解决方案是使用 XMLInputFactory
属性 IS_REPLACING_ENTITY_REFERENCES
设置为 false
。
public static void main(String[] args) throws Exception
{
String doc = "<doc> </doc>";
ByteArrayInputStream is = new ByteArrayInputStream(doc.getBytes());
XMLInputFactory xif = XMLInputFactory.newFactory();
xif.setProperty(javax.xml.stream.XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
XMLStreamReader xr = xif.createXMLStreamReader(is);
while(xr.hasNext())
{
int t = xr.getEventType();
switch(t) {
case XMLEvent.ENTITY_REFERENCE:
System.out.println("Entity: "+ xr.getLocalName());
break;
case XMLEvent.START_DOCUMENT:
System.out.println("Start Document");
break;
case XMLEvent.START_ELEMENT:
System.out.println("Start Element: " + xr.getLocalName());
break;
case XMLEvent.END_DOCUMENT:
System.out.println("End Document");
break;
case XMLEvent.END_ELEMENT:
System.out.println("End Element: " + xr.getLocalName());
break;
default:
System.out.println("Other: ");
break;
}
xr.next();
}
}
输出:
Start Document
Start Element: doc
Entity: nbsp null
End Element: doc
但是如果您真的需要内存中的完整 DOM 树,那么这可能需要在您的代码中进行过多的重写。
我花了一个小时跟踪 DOM 实现,但找不到任何方法让 DOM 解析器从 XMLStreamReader
读取数据。
代码中也有证据表明内部 DOM 解析器实现有一个类似于 IS_REPLACING_ENTITY_REFERENCES
的选项,但我找不到从外部设置它的任何方法。
关于java - 如何让 XML 解析器知道所有字符实体引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38771056/