xpath不返回任何值

时间:2013-11-04 13:40:00

标签: java xml xpath

我尝试使用Xpath来读取XML。我没有从评估中获得任何结果的问题 公共类XPathUtils实现IXPath {

private Document doc;
private XPath xpath;

public XPathUtils(String baseString) throws HanaHttpConnectivityException {
    DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();

    try {
        // resolve attacks on XML parsers - Fortify issue
        docFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); //$NON-NLS-1$
        docFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); //$NON-NLS-1$
        docFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); //$NON-NLS-1$
        docFactory.setFeature("http://xml.org/sax/features/namespaces", false); //$NON-NLS-1$
        docFactory.setFeature("http://xml.org/sax/features/validation", false); //$NON-NLS-1$
        docFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); //$NON-NLS-1$  
        docFactory.setXIncludeAware(false);
        docFactory.setValidating(false);
        docFactory.setNamespaceAware(true);

        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        InputStream inputs = new ByteArrayInputStream(baseString.getBytes());
        doc = docBuilder.parse(inputs);
        inputs.close();
        xpath = XPathFactory.newInstance().newXPath();
    } catch (ParserConfigurationException e) {
        throw new HanaHttpConnectivityException(e);
    } catch (SAXException e) {
        throw new HanaHttpConnectivityException(e);
    } catch (IOException e) {
        throw new HanaHttpConnectivityException(e);
    }

}

public Object getObjectValue(String strValue) throws HanaHttpConnectivityException {

    try {
        XPathExpression xpathExp = xpath.compile(strValue);
        return xpathExp.evaluate(doc,XPathConstants.NODESET);
    } catch (XPathExpressionException e) {
        throw new HanaHttpConnectivityException(e);
    }

}

public String getElementValue(String strValue) throws HanaHttpConnectivityException {

    try {
        XPathExpression xpathExp = xpath.compile(strValue);
        return xpathExp.evaluate(doc);
    } catch (XPathExpressionException e) {
        throw new HanaHttpConnectivityException(e);
    }

}

}

主要功能

    try {
        XPathUtils xpathUtil = new XPathUtils(metadata);
        Object commandValue = xpathUtil.getObjectValue("/edmx:Edmx/edmx:DataServices/Schema");
        NodeList nodes = (NodeList) commandValue;
        for (int i = 0; i < nodes.getLength(); i++) {
             String test2 = nodes.item(i).getNodeValue(); 
            }

这是XML

     <?xml version="1.0" encoding="utf-8"?>
    <edmx:Edmx 
        xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
         <edmx:DataServices 
                        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"         m:DataServiceVersion="3.0">
    <Schema 
        xmlns:cg="http://schemas.microsoft.com/ado/2006/04/codegeneration" 
        xmlns:sap="http://www.sap.com/Protocols/SAPData" 
        xmlns:rdl="http://www.sap.com/Protocols/SAPData/RDL" 
        xmlns="http://schemas.microsoft.com/ado/2009/11/edm" 
        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
        xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" Namespace="app2">
        <ComplexType Name="ApplicationView">
            <Property Name="__ID" Type="Edm.Int64" Nullable="false"/>
        </ComplexType>
        <EntityType Name="test1_entityType">
            <Key>
                <PropertyRef Name="__ID"/>
            </Key>
            <Property Name="__ID" Type="Edm.Int64" Nullable="false"/>
        </EntityType>
        <EntityType Name="test2_entityType">
            <Key>
                <PropertyRef Name="__ID"/>
            </Key>
            <Property Name="__ID" Type="Edm.Int64" Nullable="false"/>
        </EntityType>
        <EntityContainer Name="__container" m:IsDefaultEntityContainer="true">
            <EntitySet Name="test1" EntityType="app2.test1_entityType"/>
            <EntitySet Name="test2" EntityType="app2.test2_entityType"/>
            <FunctionImport Name="action1" IsSideEffecting="true" IsBindable="true" rdl:source-object="action">
                <Parameter Name="bindingParam" Type="app2.test1_entityType"/>
            </FunctionImport>
            <FunctionImport Name="action2" IsSideEffecting="true" IsBindable="true" rdl:source-object="action">
                <Parameter Name="bindingParam" Type="app2.test1_entityType"/>
            </FunctionImport>
            <FunctionImport Name="action3" IsSideEffecting="true" IsBindable="true" rdl:source-object="action">
                <Parameter Name="bindingParam" Type="app2.test2_entityType"/>
            </FunctionImport>
            <FunctionImport Name="action4" IsSideEffecting="true" IsBindable="true" rdl:source-object="action">
                <Parameter Name="bindingParam" Type="app2.test2_entityType"/>
            </FunctionImport>
            <FunctionImport Name="globalAction" IsSideEffecting="true" IsBindable="false" rdl:source-object="action"/>
            <FunctionImport Name="ApplicationView" IsSideEffecting="false" IsBindable="false" rdl:source-object="view">
                <ReturnType Type="Collection(ApplicationView)"/>
            </FunctionImport>
        </EntityContainer>
    </Schema>
    <Schema 
        xmlns:cg="http://schemas.microsoft.com/ado/2006/04/codegeneration" 
        xmlns:sap="http://www.sap.com/Protocols/SAPData" 
        xmlns:rdl="http://www.sap.com/Protocols/SAPData/RDL" 
        xmlns="http://schemas.microsoft.com/ado/2009/11/edm" 
        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
        xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" Namespace="app2.metadataParent">
        <ComplexType Name="MyView">
            <Property Name="myElement" Type="Edm.String" MaxLength="5000" Unicode="true"/>
        </ComplexType>
        <EntityType Name="MyEntity_entityType">
            <Key>
                <PropertyRef Name="__ID"/>
            </Key>
            <Property Name="__ID" Type="Edm.Int64" Nullable="false"/>
            <Property Name="myElement" Type="Edm.String" MaxLength="5000" Unicode="true"/>
        </EntityType>
        <EntityContainer Name="__container" m:IsDefaultEntityContainer="false">
            <EntitySet Name="MyEntity" EntityType="app2.metadataParent.MyEntity_entityType"/>
            <FunctionImport Name="myAction" IsSideEffecting="true" IsBindable="true" rdl:source-object="action">
                <ReturnType Type="Edm.String" MaxLength="5000" Unicode="true"/>
                <Parameter Name="bindingParam" Type="app2.metadataParent.MyEntity_entityType"/>
            </FunctionImport>
            <FunctionImport Name="MyView" IsSideEffecting="false" IsBindable="false" rdl:source-object="view">
                <ReturnType Type="Collection(MyView)"/>
            </FunctionImport>
        </EntityContainer>
    </Schema>
    <Schema 
        xmlns:cg="http://schemas.microsoft.com/ado/2006/04/codegeneration" 
        xmlns:sap="http://www.sap.com/Protocols/SAPData" 
        xmlns:rdl="http://www.sap.com/Protocols/SAPData/RDL" 
        xmlns="http://schemas.microsoft.com/ado/2009/11/edm" 
        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
        xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" Namespace="app2.metadataParent.metadata2Child">
        <EntityType Name="xxx_entityType">
            <Key>
                <PropertyRef Name="__ID"/>
            </Key>
            <Property Name="__ID" Type="Edm.Int64" Nullable="false"/>
        </EntityType>
        <EntityContainer Name="__container" m:IsDefaultEntityContainer="false">
            <EntitySet Name="xxx" EntityType="app2.metadataParent.metadata2Child.xxx_entityType"/>
            <FunctionImport Name="xxxyyy" IsSideEffecting="true" IsBindable="true" rdl:source-object="action">
                <Parameter Name="bindingParam" Type="app2.metadataParent.metadata2Child.xxx_entityType"/>
            </FunctionImport>
        </EntityContainer>
    </Schema>
    <Schema 
        xmlns:cg="http://schemas.microsoft.com/ado/2006/04/codegeneration" 
        xmlns:sap="http://www.sap.com/Protocols/SAPData" 
        xmlns:rdl="http://www.sap.com/Protocols/SAPData/RDL" 
        xmlns="http://schemas.microsoft.com/ado/2009/11/edm" 
        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
        xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" Namespace="app2.metadataNotChild">
        <EntityType Name="ffgg_entityType">
            <Key>
                <PropertyRef Name="__ID"/>
            </Key>
            <Property Name="__ID" Type="Edm.Int64" Nullable="false"/>
        </EntityType>
        <EntityContainer Name="__container" m:IsDefaultEntityContainer="false">
            <EntitySet Name="ffgg" EntityType="app2.metadataNotChild.ffgg_entityType"/>
            <FunctionImport Name="gghh" IsSideEffecting="true" IsBindable="true" rdl:source-object="action">
                <Parameter Name="bindingParam" Type="app2.metadataNotChild.ffgg_entityType"/>
            </FunctionImport>
        </EntityContainer>
    </Schema>
</edmx:DataServices>
</edmx:Edmx>

我也尝试使用

   "//edmx:Edmx//edmx:DataServices//Schema/Namespace"
   "//edmx:Edmx//edmx:DataServices//Schema//Namespace"

你知道为什么我没有成功获得任何结果吗?

1 个答案:

答案 0 :(得分:1)

您的Schema元素

xmlns="http://schemas.microsoft.com/ado/2009/11/edm"

这意味着它(及其所有未加前缀的子节点)都在此命名空间中,因此在XPath表达式中不会被.../Schema匹配(XPath表达式中的未加前缀的名称始终引用没有名称空间。)

您需要向XPath实例提供NamespaceContext,告诉他们如何解析命名空间URI的前缀。遗憾的是,标准Java类库中没有此接口的默认实现,但是存在第三方实现,例如SimpleNamespaceContext from the Spring Framework,或者创建自己的相当简单。以Spring实现为例,它是这样的:

public class XPathUtils implements IXPath {

    private Document doc;
    private XPath xpath;
    private SimpleNamespaceContext nsCtx;

    public XPathUtils(String baseString) throws HanaHttpConnectivityException {
      // as before
      // .......
      xpath = XPathFactory.newInstance().newXPath();
      nsCtx = new SimpleNamespaceContext();
      xpath.setNamespaceContext(nsCtx);
    }

    public Object getObjectValue(String strValue, String... namespaces) throws HanaHttpConnectivityException {
        try {
            if(namespaces != null) {
              // namespaces array is [prefix1, uri1, prefix2, uri2, ...]
              for(int i = 0; i < namespaces.length; i++) {
                nsCtx.bindNamespaceUri(namespaces[i], namespaces[++i]);
              }
            }
            XPathExpression xpathExp = xpath.compile(strValue);
            return xpathExp.evaluate(doc,XPathConstants.NODESET);
        } catch (XPathExpressionException e) {
            throw new HanaHttpConnectivityException(e);
        } finally {
            nsCtx.clear();
        }

    }
}

除了为edmx提供http://schemas.microsoft.com/ado/2007/06/edmx前缀的绑定之外,您还需要将前缀(例如edm)绑定到http://schemas.microsoft.com/ado/2009/11/edm命名空间并使用你的XPath中的前缀:

NodeList namespaceAttributes = (NodeList)xpathUtil.getObjectValue(
    "/edmx:Edmx/edmx:DataServices/edm:Schema/@Namespace",
      "edmx", "http://schemas.microsoft.com/ado/2007/06/edmx",
      "edm",  "http://schemas.microsoft.com/ado/2009/11/edm");