【问题标题】:Simple way to get execute an Xpath against a String in Java?在 Java 中针对字符串执行 Xpath 的简单方法?
【发布时间】:2016-09-13 01:09:56
【问题描述】:

我知道已经多次询问(并回答)了与此问题类似的问题,并且我尝试了许多建议,但由于某种原因,我无法使其正常工作。

我在 String 变量中有一个 XML 文档(在“compositeBodyLine”中),我想对该 XML 文档执行 Xpath 搜索并从该 Xpath 搜索中获取结果。

我该怎么做?

这是我尝试过的一个例子(或者实际上合并了我发现的几种不同的东西:

 // From: http://javarevisited.blogspot.com/2012/12/create-and-evaluate-xpath-java-example-tutorial-program.html

  //Create DocumentBuilderFactory for reading xml file
  DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  DocumentBuilder builder = factory.newDocumentBuilder();

  InputStream inputStream = new    ByteArrayInputStream(compositeBodyLine.getBytes());
  org.w3c.dom.Document doc = builder.parse(inputStream);

   System.out.println("doc.getParentNode()=[" + doc.getParentNode().toString() + "]");

  // Create XPathFactory for creating XPath Object
  XPathFactory xPathFactory = XPathFactory.newInstance();

  // Create XPath object from XPathFactory
  XPath xpath = xPathFactory.newXPath();

  // Compile the XPath expression for getting all brands
  XPathExpression xPathExpr = xpath.compile("/soapEnv:Envelope");

  // XPath text example : executing xpath expression in java
  Object result = xPathExpr.evaluate(doc, XPathConstants.NODESET);
  System.out.println("Java Xpath text example: All brands of popular smartphones ");

  printXpathResult(result);

.
.
.
.
public static org.w3c.dom.Document loadXMLFromString(String xml) throws Exception
{
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    InputSource is = new InputSource(new StringReader(xml));
    return builder.parse(is);
}

当我尝试上面的代码时,我得到了 null 返回。我认为我看过的大多数示例都将文件作为输入,而在我的情况下,我将 XML 文档放在 String 变量中,所以如果我不得不猜测,我会猜我在带来XML 输入。

有人可以提供一个简单的方法来完成这个吗?

谢谢, 吉姆

编辑:这是输入 XML 的示例:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soapenv:Body>
        <Request xmlns:xacml-context="urn:oasis:names:tc:xacml:2.0:context:schema:os" xmlns:ns9="urn:oasis:xacml:2.0:saml:assertion:schema:os" xmlns:ns8="urn:oasis:xacml:2.0:saml:protocol:schema:os" xmlns:ns7="http://security.bea.com/ssmws/ssm-soap-types-1.0.xsd" xmlns:ns6="http://www.w3.org/2001/04/xmlenc#" xmlns:ns5="urn:oasis:names:tc:xacml:2.0:policy:schema:os" xmlns:ns4="urn:oasis:names:tc:xacml:2.0:context:schema:os" xmlns:ns3="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns="urn:oasis:names:tc:xacml:2.0:context:schema:os">
            <Subject>
                <Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-id" DataType="http://security.bea.com/ssmws/ssm-ws-1.0.wsdl#OESPrincipalInfo">

                    <AttributeValue>{name=jimXXXX1234}+(class=weblogic.security.principal.WLSUserImpl)</AttributeValue>
                </Attribute>
<!-- FOLLOWING IS **THE** GOOD WAY AND DOES WORK WITH OES FOR ROLE -->
<Attribute AttributeId="http://oracle.com/symbols/oes/attribute/group-assertion" DataType="http://security.bea.com/ssmws/ssm-ws-1.0.wsdl#OESPrincipalInfo" xsi:type="ns1:AttributeType"> 
<AttributeValue xsi:type="ns1:AttributeValueType">{name=Operators}+(class=weblogic.security.principal.WLSGroupImpl)</AttributeValue> 
</Attribute> 
            </Subject>
            <Resource>
                <Attribute AttributeId="urn:oasis:names:tc:xacml:2.0:resource:resource-id" DataType="http://www.w3.org/2001/XMLSchema#string">
                    <AttributeValue>foo/foo1/foo2</AttributeValue>
                </Attribute>
            </Resource>
            <Action>
                <Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" DataType="http://www.w3.org/2001/XMLSchema#string">
                    <AttributeValue>GET</AttributeValue>
                </Attribute>
            </Action>
<ns4:Environment xsi:type="ns4:EnvironmentType" 
     xmlns:ns4="urn:oasis:names:tc:xacml:2.0:context:schema:os" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ns4:Attribute AttributeId="http://security.bea.com/ssmws/ssm-ws-1.0.wsdl#RegisteredAttribute" 
     DataType="http://www.w3.org/2001/XMLSchema#string" xsi:type="ns4:AttributeType">
    <ns4:AttributeValue xsi:type="ns4:AttributeValueType">4444444444yes</ns4:AttributeValue> 
  </ns4:Attribute>
  <ns4:Attribute AttributeId="http://security.bea.com/ssmws/ssm-ws-1.0.wsdl#NumberOfBorrowedBooksAttribute" 
       DataType="http://www.w3.org/2001/XMLSchema#string" xsi:type="ns4:AttributeType">
        <ns4:AttributeValue xsi:type="ns4:AttributeValueType">abc</ns4:AttributeValue> 
  </ns4:Attribute>
</ns4:Environment>
                  </Request>
    </soapenv:Body>
</soapenv:Envelope>

【问题讨论】:

  • 不要使用String.getBytes() 向DOM 解析器发送字节数组。字符串本身:builder.parse(new InputSource(new StringReader(compositeBodyLine)))。 --- 你有 loadXMLFromString() 方法这样做,那你为什么不使用它????
  • 您的 XPath 表达式正在使用命名空间前缀 (soapEnv:),但是 1) 您没有定义该前缀(调用 xpath.setNamespaceContext(...) 来解决该问题),并且2) 你没有解析启用命名空间的文档(调用factory.setNamespaceAware(true) 来解决这个问题)。 --- 除此之外,当我们不知道 XML 是什么样子时,您希望我们如何提供帮助?
  • Andreas - 我在原始消息中添加了一个示例 XML。我也尝试了你关于 builder.parse(new InputSource(new StringReader(compositeBodyLine))) 的建议,但我得到了 NullPointerException。

标签: java xml xpath


【解决方案1】:

Steve,原因可能是您在 XML 上拥有的名称空间。克服这个问题的一种方法是注册命名空间。更简单的方法可能是使用本地名称。您的程序的较短版本如下所示,它确实按预期返回了一个节点集。我在这里创建了一个最低限度的测试程序,如果这适用于您可能拥有的其他 XPATH,请告诉我

import java.io.ByteArrayInputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;

public class XPathClass {
    public static void main(String[] args) throws Exception {
        String soapXML = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">    <soapenv:Body>        <Request xmlns:xacml-context=\"urn:oasis:names:tc:xacml:2.0:context:schema:os\" xmlns:ns9=\"urn:oasis:xacml:2.0:saml:assertion:schema:os\" xmlns:ns8=\"urn:oasis:xacml:2.0:saml:protocol:schema:os\" xmlns:ns7=\"http://security.bea.com/ssmws/ssm-soap-types-1.0.xsd\" xmlns:ns6=\"http://www.w3.org/2001/04/xmlenc#\" xmlns:ns5=\"urn:oasis:names:tc:xacml:2.0:policy:schema:os\" xmlns:ns4=\"urn:oasis:names:tc:xacml:2.0:context:schema:os\" xmlns:ns3=\"urn:oasis:names:tc:SAML:2.0:protocol\" xmlns:ns2=\"http://www.w3.org/2000/09/xmldsig#\" xmlns=\"urn:oasis:names:tc:xacml:2.0:context:schema:os\">            <Subject>                <Attribute AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject:subject-id\" DataType=\"http://security.bea.com/ssmws/ssm-ws-1.0.wsdl#OESPrincipalInfo\">                    <AttributeValue>{name=jimlum1234}+(class=weblogic.security.principal.WLSUserImpl)</AttributeValue>                </Attribute><!-- FOLLOWING IS **THE** GOOD WAY AND DOES WORK WITH OES FOR ROLE --><Attribute AttributeId=\"http://oracle.com/symbols/oes/attribute/group-assertion\" DataType=\"http://security.bea.com/ssmws/ssm-ws-1.0.wsdl#OESPrincipalInfo\" xsi:type=\"ns1:AttributeType\"> <AttributeValue xsi:type=\"ns1:AttributeValueType\">{name=Operators}+(class=weblogic.security.principal.WLSGroupImpl)</AttributeValue> </Attribute>             </Subject>            <Resource>                <Attribute AttributeId=\"urn:oasis:names:tc:xacml:2.0:resource:resource-id\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">                    <AttributeValue>foo/foo1/foo2</AttributeValue>                </Attribute>            </Resource>            <Action>                <Attribute AttributeId=\"urn:oasis:names:tc:xacml:1.0:action:action-id\" DataType=\"http://www.w3.org/2001/XMLSchema#string\">                    <AttributeValue>GET</AttributeValue>                </Attribute>            </Action><ns4:Environment xsi:type=\"ns4:EnvironmentType\"      xmlns:ns4=\"urn:oasis:names:tc:xacml:2.0:context:schema:os\"      xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">  <ns4:Attribute AttributeId=\"http://security.bea.com/ssmws/ssm-ws-1.0.wsdl#RegisteredAttribute\"      DataType=\"http://www.w3.org/2001/XMLSchema#string\" xsi:type=\"ns4:AttributeType\">    <ns4:AttributeValue xsi:type=\"ns4:AttributeValueType\">4444444444yes</ns4:AttributeValue>   </ns4:Attribute>  <ns4:Attribute AttributeId=\"http://security.bea.com/ssmws/ssm-ws-1.0.wsdl#NumberOfBorrowedBooksAttribute\"        DataType=\"http://www.w3.org/2001/XMLSchema#string\" xsi:type=\"ns4:AttributeType\">        <ns4:AttributeValue xsi:type=\"ns4:AttributeValueType\">abc</ns4:AttributeValue>   </ns4:Attribute></ns4:Environment>                  </Request>    </soapenv:Body></soapenv:Envelope>";
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(new ByteArrayInputStream(soapXML.getBytes()));

        XPathFactory xPathFactory = XPathFactory.newInstance();

        // Create XPath object from XPathFactory
        XPath xpath = xPathFactory.newXPath();

        // Compile the XPath expression for getting all brands
        XPathExpression xPathEnvelopeExpr = xpath.compile("//*[local-name()='Envelope']");
        Object result = xPathEnvelopeExpr.evaluate(doc, XPathConstants.NODESET);
        System.out.println("Java Xpath text example: All brands of popular smartphones " + result);

    }

}

【讨论】:

  • Ramachandran G A - 我认为这接近于满足我的需要,但是,仅供参考,我从我发布的代码中添加了“printXpathResult()”方法,稍微修改以输出节点值和name,它显示节点名称正常,但节点值 (nodes.item(i).getNodeValue()) 返回为 null。
  • Ramachandran G A - 好的,我能够得到值。我曾经使用“nodes.item(i).getTextContent()”而不是“nodes.item(i).getNoteValue()”。谢谢!!
猜你喜欢
  • 2011-05-10
  • 1970-01-01
  • 2013-05-18
  • 2014-02-09
  • 1970-01-01
  • 2014-12-22
  • 1970-01-01
  • 1970-01-01
  • 2014-11-30
相关资源
最近更新 更多