【问题标题】:xpath doesn't return any valuexpath 不返回任何值
【发布时间】:2013-11-04 22:19:15
【问题描述】:

我尝试使用 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"

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

【问题讨论】:

    标签: java xml xpath


    【解决方案1】:

    你的Schema 元素有

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

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

    您需要为您的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");
    

    【讨论】:

    • 此外,您提供的 xml 无效:文件末尾应该有一个 &lt;/edmx:Edmx&gt; ...
    • 我忘了添加
    • 我不明白在这种情况下获取模式值的路径应该是什么,例如命名空间或实体类型
    • @user1365697 Namespace 是一个属性,所以(假设是正确的 NamespaceContext)类似/edmx:Edmx/edmx:DataServices/edm:Schema/@Namespace 的东西会给你一个NodeList 的所有Namespace 属性的不同Schema 元素。对于像EntityType 这样的元素,您需要使用绑定到http://schemas.microsoft.com/ado/2009/11/edm 的前缀,与Schema 元素相同。
    • 我试过这个 /edmx:Edmx/edmx:DataServices/edm:Schema/@Namespace 但没有用
    猜你喜欢
    • 2011-09-05
    • 1970-01-01
    • 2021-09-19
    • 1970-01-01
    • 1970-01-01
    • 2022-09-28
    • 2017-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多