【问题标题】:In Java how do I evaluate XPATH expression on XML using SAX Parser?在 Java 中,如何使用 SAX Parser 评估 XML 上的 XPATH 表达式?
【发布时间】:2014-11-18 14:18:45
【问题描述】:

在 Java 中,如何使用 SAX Parser 评估 XML 上的 XPATH 表达式?

需要更动态的方式,因为 XML 格式不固定。所以我应该能够通过以下

  1. xpath 作为字符串
  2. xml 作为字符串/输入源

类似于 Utility.evaluate("/test/@id='123'", "")

【问题讨论】:

    标签: java xml parsing xpath sax


    【解决方案1】:

    这是一个例子:

    //First create a Document
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder(); 
    Document doc = db.parse(new File("test.xml"));
    
    //Init the xpath factory
    XPath xPath =  XPathFactory.newInstance().newXPath();
    String expression = "/company/employee";
    
    //read a nodelist using xpath
    NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(doc, XPathConstants.NODESET);
    

    编辑:

    如果你想使用 SAX 解析器,那么你不能使用 Java 的 XPath 对象,见https://docs.oracle.com/javase/7/docs/api/javax/xml/xpath/package-summary.html

    XPath 语言为从 XML 文档中选择节点提供了一种简单、简洁的语法。 XPath 还提供了将 XML 文档对象模型 (DOM) 树中的节点转换为布尔值、双精度值或字符串值的规则。 XPath 是 W3C 定义的语言和官方 W3C 推荐; W3C 承载 XML 路径语言 (XPath) 版本 1.0 规范。

    XPath 始于 1999 年,作为 XSLT 和 XPointer 语言的补充,但最近作为一种独立语言变得流行,因为单个 XPath 表达式可用于替换多行 DOM API 代码。

    如果您想使用 SAX,可以查看此问题中详细说明的库:Is there any XPath processor for SAX model?

    虽然 XPath 的机制并不真正适合 SAX。实际上,使用 SAX 解析器不会在内存中创建 XML 树。因此,您不能有效地使用 XPath,因为它不会看到未加载的节点。

    【讨论】:

    • 我需要使用 SAX 解析器而不是 DOM 解析器。
    【解决方案2】:

    只有一小部分 XPath 适合流式评估,即在解析输入文档时即时评估。因此,周围没有很多流式 XPath 处理器;其中大部分是学术研究项目的产物。

    您可以尝试的一件事是 Saxon-EE 流式 XQuery。这是 XQuery 的一个小子集,它允许流式执行(它将允许像您的示例这样的表达式)。详情在

    http://www.saxonica.com/documentation/#!sourcedocs/streaming/streamed-query

    【讨论】:

      【解决方案3】:

      Oracle 用于 Java 的 XQuery 处理器将“动态”流式处理路径表达式: https://docs.oracle.com/database/121/ADXDK/adx_j_xqj.htm#ADXDK99930

      具体来说,这里有关于流式传输的信息,包括一个示例: https://docs.oracle.com/database/121/ADXDK/adx_j_xqj.htm#ADXDK119

      但它不会使用 SAX 进行流式传输。您必须将输入 XML 绑定为 StAX、InputStream 或 Reader 才能获得流式评估。

      【讨论】:

        【解决方案4】:

        可以在使用 Saxon 的 XPath 中使用 SAXSource但是 - 这很重要 - 请注意,底层实现几乎肯定仍会加载和缓冲内存中的部分或全部文档以评估 xpath。它可能不会是一个完整的 DOM 树(Saxon 依赖于自己的称为 TinyTree 的结构,它支持延迟加载和各种其他优化),因此它比使用大多数 DOM 实现要好,但它仍然涉及将文档加载到记忆。如果您担心大型数据集的内存负载,它可能对您没有多大帮助,您最好使用其他人建议的流式 xpath/xquery 选项之一。

        实用程序方法的实现可能如下所示:

        import java.io.StringReader;
        
        import javax.xml.namespace.QName;
        import javax.xml.parsers.SAXParser;
        import javax.xml.parsers.SAXParserFactory;
        import javax.xml.transform.sax.SAXSource;
        import javax.xml.xpath.XPath;
        import javax.xml.xpath.XPathConstants;
        
        import org.xml.sax.InputSource;
        
        import net.sf.saxon.xpath.XPathFactoryImpl;
        
        public class XPathUtils {
        
            public static Object evaluate(String xpath, String xml, QName returnType)
                    throws Exception {
                SAXParser parser = (SAXParser) SAXParserFactory.newInstance()
                        .newSAXParser();
                InputSource source = new InputSource(new StringReader(xml));
                SAXSource saxSource = new SAXSource(parser.getXMLReader(), source);
                XPath xPath = new XPathFactoryImpl().newXPath();
                return xPath.evaluate(xpath, saxSource, returnType);
            }
        
            public static String xpathString(String xpath, String xml)
                    throws Exception {
                return (String) evaluate(xpath, xml, XPathConstants.STRING);
            }
        
            public static boolean xpathBool(String xpath, String xml) throws Exception {
                return (Boolean) evaluate(xpath, xml, XPathConstants.BOOLEAN);
            }
        
            public static Number xpathNumber(String xpath, String xml) throws Exception {
                return (Number) evaluate(xpath, xml, XPathConstants.NUMBER);
            }
        
            public static void main(String[] args) throws Exception {
                System.out.println(xpathString("/root/@id", "<root id='12345'/>"));
            }
        }
        

        这是因为 Saxon XPath 实现支持 SAXSource 作为 evaluate() 的上下文。请注意,使用内置的 Apaache XPath 实现尝试此操作将引发异常。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-23
          • 2019-04-08
          • 1970-01-01
          • 1970-01-01
          • 2022-11-07
          相关资源
          最近更新 更多