有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何处理未知的实体引用?

我正在解析(很多)包含实体引用的XML文件,这些实体引用我事先不知道(不能改变这个事实)

例如:

xml = "<tag>I'm content with &funny; &entity; &references;.</tag>"

当我尝试使用以下代码解析此代码时:

final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
final DocumentBuilder db = dbf.newDocumentBuilder();
final InputSource is = new InputSource(new StringReader(xml));
final Document d = db.parse(is);

我得到以下例外情况:

org.xml.sax.SAXParseException: The entity "funny" was referenced, but not declared.

但是,我想要实现的是,解析器用空字符串“”替换每个未声明(解析器未知)的实体。 或者更好,是否有一种方法可以将映射传递给解析器,如:

Map<String,String> entityMapping = ...
entityMapping.put("funny","very");
entityMapping.put("entity","important");
entityMapping.put("references","stuff");

这样我就可以做到以下几点:

final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
final DocumentBuilder db = dbf.newDocumentBuilder();
final InputSource is = new InputSource(new StringReader(xml));

db.setEntityResolver(entityMapping);
final Document d = db.parse(is);

如果我使用此示例代码从文档中获取文本,我将收到:

I'm content with very important stuff.

有什么建议吗?当然,我已经很乐意用空字符串替换未知实体

谢谢


共 (3) 个答案

  1. # 1 楼答案

    StAX API支持这一点。看看XMLInputFactory,它有一个runtime property,它决定内部实体是被扩展,还是留在原地。如果设置为false,则StAX事件流将包含EntityReference的实例,以表示未展开的实体

    如果您仍然想要一个DOM作为最终结果,可以像这样将其链接在一起:

    XMLInputFactory inputFactory = XMLInputFactory.newInstance();
    inputFactory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
    Transformer transformer = TransformerFactory.newInstance().newTransformer();
    
    String xml = "my xml";
    StringReader xmlReader = new StringReader(xml);
    XMLEventReader eventReader = inputFactory.createXMLEventReader(xmlReader);
    StAXSource source = new StAXSource(eventReader);
    DOMResult result = new DOMResult();
    
    transformer.transform(source, result);
    
    Node document = result.getNode();
    

    在这种情况下,生成的DOM将包含org.w3c.dom.EntityReference的节点与文本节点混合。然后,您可以根据自己的需要处理这些问题

  2. # 2 楼答案

    可以在文件的开头添加实体。查看更多信息

    您还可以看看this thread,其中似乎有人实现了EntityResolver接口(您也可以实现EntityResolver!)您可以在其中动态处理实体(例如,使用建议的地图)

    WARNING: there is a bug!在jdk6中,但您可以在jdk5中尝试

  3. # 3 楼答案

    既然XML输入似乎可以作为字符串使用,那么就不能用正则表达式替换进行简单的预处理吗

    xml = "...";
    
    /* replace entities before parsing */
    for (Map.Entry<String,String> entry : entityMapping.entrySet()) {
       xml = xml.replaceAll("&" + entry.getKey() + ";", entry.getValue());
    }
    
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    ...
    

    这是一个非常复杂的过程,您可能需要花费一些额外的精力来确保regexp只匹配它们真正应该匹配的地方(想想^{),但至少它是

    当然,有比多次调用replaceAll()更有效的方法来实现相同的效果