Java如何从输入流(InputStream)解析XML

Java中解析InputStream的XML需选SAX、DOM或StAX:DOM适合小中文件但占内存;SAX事件驱动、低内存;StAX拉模式、易控且高效;均须防XXE、正确关流、处理BOM。

Java中从InputStream解析XML,核心是使用标准的XML解析API(如SAX、DOM或StAX),将输入流作为数据源传入解析器。关键在于确保流未被提前读取或关闭,并选择合适解析方式。

使用DOM解析器(适合小到中等XML)

DOM会将整个XML加载为内存中的树结构,便于随机访问节点,但不适用于大文件。

  • DocumentBuilder配合InputSource包装InputStream
  • 注意:若InputStream含BOM(如UTF-8带签名),可能导致解析失败,建议用InputStreamReader显式指定编码并跳过BOM
  • 示例代码片段:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(inputStream));

使用SAX解析器(适合大文件、低内存占用)

SAX是事件驱动的流式解析,不构建内存树,适合处理大XML或只需提取部分信息的场景。

  • 实现DefaultHandler子类,重写startElementcharacters等方法
  • 直接传入InputStreamXMLReader.parse(),无需额外包装
  • 推荐设置setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)防止XXE攻击

使用StAX解析器(推荐:兼顾流式与编程便利)

StAX(Streaming API for XML)是Java内置的拉模式解析器,比SAX更易控制流程,且无需完整加载文档。

  • XMLInputFactory创建XMLStreamReader
  • 直接传入InputStream,支持设置字符编码(如factory.createXMLStreamReader(inputStream, "UTF-8")
  • 通过next()getEventType()遍历事件,用getElementText()快速获取文本内容

注意事项与常见问题

无论哪种方式,都要注意:

  • InputStream只能被读取一次,重复解析需重新获取流(如重置、重开或缓存字节)
  • 务必在finally块或try-with-resources中关闭流(DOM/SAX需手动关;StAX的XMLStreamReader也建议调用close()
  • 避免使用已弃用的javax.xml.parsers.SAXParserFactory.newInstance().newSAXParser()旧式写法,优先用标准工厂模式
  • 如XML来自网络或不可信源,必须禁用外部实体解析,防范XXE漏洞