GVKun编程网logo

如何使用XPath在Java中使用名称空间查询XML?(xpath 命名空间)

8

本文将介绍如何使用XPath在Java中使用名称空间查询XML?的详细情况,特别是关于xpath命名空间的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些

本文将介绍如何使用XPath在Java中使用名称空间查询XML?的详细情况,特别是关于xpath 命名空间的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于Java XML使用方法-使用xpath在XML文件中的节点列表中查找和添加/替换更多子节点、Java XPath:使用默认名称空间xmlns的查询、java – VTD-XML大数据xPathExpression不使用名称空间、java – 使用XmlPullParser处理Xml名称空间的知识。

本文目录一览:

如何使用XPath在Java中使用名称空间查询XML?(xpath 命名空间)

如何使用XPath在Java中使用名称空间查询XML?(xpath 命名空间)

当我的XML看起来像这样(no xmlns)时,我可以使用XPath轻松查询它/workbook/sheets/sheet[1]

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><workbook>  <sheets>    <sheet name="Sheet1" sheetId="1" r:id="rId1"/>  </sheets></workbook>

但是当看起来像这样我就不能

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">  <sheets>    <sheet name="Sheet1" sheetId="1" r:id="rId1"/>  </sheets></workbook>

有任何想法吗?

答案1

小编典典

在第二个示例XML文件中,元素绑定到名称空间。你的XPath尝试处理绑定到默认“无名称空间”名称空间的元素,因此它们不匹配。

首选方法是使用名称空间前缀注册名称空间。它使你的XPath更加易于开发,读取和维护。

但是,并不一定要注册名称空间并在XPath中使用名称空间前缀。

你可以公式化一个XPath表达式,该表达式对元素使用通用匹配,并使用谓词过滤器来限制所需local-name()和的匹配namespace-uri()。例如:

/*[local-name()=''workbook''    and namespace-uri()=''http://schemas.openxmlformats.org/spreadsheetml/2006/main'']  /*[local-name()=''sheets''      and namespace-uri()=''http://schemas.openxmlformats.org/spreadsheetml/2006/main'']  /*[local-name()=''sheet''      and namespace-uri()=''http://schemas.openxmlformats.org/spreadsheetml/2006/main''][1]

如你所见,它会产生一个非常冗长且冗长的XPath语句,该语句很难读取(和维护)。

你也可以只匹配local-name()元素的,而忽略名称空间。例如:

/*[local-name()=''workbook'']/*[local-name()=''sheets'']/*[local-name()=''sheet''][1]

但是,你冒着匹配错误元素的风险。如果你的XML混合使用了相同的词汇表(对于该实例而言可能不是问题)local-name(),则你的XPath可能匹配错误的元素并选择了错误的内容:

Java XML使用方法-使用xpath在XML文件中的节点列表中查找和添加/替换更多子节点

Java XML使用方法-使用xpath在XML文件中的节点列表中查找和添加/替换更多子节点

Xpath专门用于跟踪/读取xml,但不能用于修改xml。

因此,我将代码从使用XPath更改为使用DOM Parser。

try
            {
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        Document doc = docBuilder.newDocument();
        // Map root element
        Element rootElement = doc.createElement("map");
        doc.appendChild(rootElement);
        //ROOT map
        
        //1. ankomstDato
        Element ankomstDato = doc.createElement("string");
        Attr attrType_ankomstDato = doc.createAttribute("key");
        attrType_ankomstDato.setValue("ankomstDato");
        ankomstDato.setAttributeNode(attrType_ankomstDato);
        ankomstDato.appendChild(doc.createTextNode(ankomstDato_value));
        rootElement.appendChild(ankomstDato);

        //. planlagtAntallPerUndergruppe
        // planlagtAntallPerUndergruppe element
        

        if (planlagtAntallPerUndergruppe_Count !=0){
            Element planlagtAntallPerUndergruppe = doc.createElement("array");
            rootElement.appendChild(planlagtAntallPerUndergruppe);

            Attr attr = doc.createAttribute("key");
            attr.setValue("planlagtAntallPerUndergruppe");
            planlagtAntallPerUndergruppe.setAttributeNode(attr);

            for (int i = 0; i < planlagtAntallPerUndergruppe_Count; i ++){
                //to add "map" element
                Element map1 = doc.createElement("map");
                planlagtAntallPerUndergruppe.appendChild(map1);


                    // antall element
                    Element antall = doc.createElement("number");
                    Attr attrType = doc.createAttribute("key");
                    attrType.setValue("antall");
                    antall.setAttributeNode(attrType);
                    antall.appendChild(doc.createTextNode(planlagtAntallPerUndergruppe_antall_value[i]));
                    map1.appendChild(antall);
                    
                    //kode element
                    Element kode = doc.createElement("string");
                    Attr attrType1 = doc.createAttribute("key");
                    attrType1.setValue("kode");
                    kode.setAttributeNode(attrType1);
                    kode.appendChild(doc.createTextNode(planlagtAntallPerUndergruppe_kode_value[i]));
                    map1.appendChild(kode);
            }
        }
        //end planlagtAntallPerUndergruppe

        
        // Write the content into XML file
        DOMSource source = new DOMSource(doc);
        StreamResult result = new StreamResult(new File("E:/utils/students-new.xml"));
        
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        // Beautify the format of the resulted XML
        transformer.setOutputProperty(OutputKeys.INDENT,"yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount","4");
        transformer.transform(source,result);
         }
        catch(Exception ex)
          {
            ex.printStackTrace();
        }
    
      }
,

将收集的数组作为参数传递到Write2XMLfile方法中

public void Write2XMLfile(String[] planlagtAntallPerUndergruppe_antall_value,String[] planlagtAntallPerUndergruppe_kode_value) {
   
   try {
       
         DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
         DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
         Document doc = dBuilder.newDocument();
         
         Element rootElement = doc.createElement("map");
         doc.appendChild(rootElement);

         Element mainString = doc.createElement("string");
         mainString.setAttribute("key","ankomstDato");
         rootElement.appendChild(mainString).setTextContent("2020-08-20");
         
         
         Element array = doc.createElement("array");
         array.setAttribute("key","planlagtAntallPerUndergruppe");
         rootElement.appendChild(array);
         

         if(planlagtAntallPerUndergruppe_antall_value.length>0){
             for (int i = 0; i < planlagtAntallPerUndergruppe_antall_value.length; i++) {
                Element map = doc.createElement("map");
                array.appendChild(map);
                
                Element number =  doc.createElement("number");
                number.setAttribute("key","antall");
                map.appendChild(number).setTextContent(planlagtAntallPerUndergruppe_antall_value[i]);
                
                Element string =  doc.createElement("string");
                string.setAttribute("key","kode");
                map.appendChild(string).setTextContent(planlagtAntallPerUndergruppe_kode_value[i]);
            }
         }

         TransformerFactory transformerFactory = TransformerFactory.newInstance();
         Transformer transformer = transformerFactory.newTransformer();
         transformer.setOutputProperty(OutputKeys.INDENT,"yes");
         transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount","2");
         DOMSource source = new DOMSource(doc);
         StreamResult output = new StreamResult(new File("output.xml"));
         transformer.transform(source,output);
         
      } catch (Exception e) {
         e.printStackTrace();
      }
}

output.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<map>
  <string key="ankomstDato">2020-08-20</string>
  <array key="planlagtAntallPerUndergruppe">
    <map>
      <number key="antall">67</number>
      <string key="kode">SLAKTEGRIS</string>
    </map>
    <map>
      <number key="antall">4</number>
      <string key="kode">UNGSAU</string>
    </map>
  </array>
</map>

Java XPath:使用默认名称空间xmlns的查询

Java XPath:使用默认名称空间xmlns的查询

我要对此文件执行XPath查询(显示的摘录):

<?xml version="1.0" encoding="UTF-8"?><!-- MetaDataAPI generated on: Friday, May 25, 2007 3:26:31 PM CEST --><ModelClass xmlns="http://xml.sap.com/2002/10/metamodel/webdynpro" xmlns:IDX="urn:sap.com:WebDynpro.ModelClass:2.0">    <ModelClass.Parent>        <Core.Reference package="com.test.mypackage" name="ModelName" type="Model"/>

这是我正在使用的代码的摘要:

DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = domFactory.newDocumentBuilder();Document document = builder.parse(new File(testFile));XPathFactory factory = XPathFactory.newInstance();XPath xpath = factory.newXPath();xpath.setNamespaceContext( new NamespaceContext() {    public String getNamespaceURI(String prefix) {...String result = xpath.evaluate(xpathQueryString, document);System.out.println(result);

我面临的问题是,在XPath查询中引用默认名称空间时,不会调用getNamespaceURI方法来解决它。例如,此查询不提取任何内容:

//xmlns:ModelClass.Parent/xmlns:Core.Reference[@type=\"Model\"]/@package

现在,我尝试通过用xmlns假前缀替换来“诱骗”解析器d,然后相应地编写getNamespaceURI方法(以便http://xml.sap.com/2002/10/metamodel/webdynprod遇到问题时返回)。在这种情况下,将getNamespaceURI调用,但是XPath表达式求值的结果始终是一个空字符串。

如果我从文件和XPath查询表达式中删除名称空间,则可以获得所需的字符串(com.test.mypackage)。

有没有办法使默认名称空间正常工作?

答案1

小编典典

在您的Namespace上下文中,将您选择的前缀(例如df)绑定到文档中的名称空间URI

xpath.setNamespaceContext( new NamespaceContext() {    public String getNamespaceURI(String prefix) {      switch (prefix) {        case "df": return "http://xml.sap.com/2002/10/metamodel/webdynpro";        ...       }    });

然后在路径表达式中使用该前缀来限定元素名称,例如/df:ModelClass/df:ModelClass.Parent/df:Core.Reference[@type= ''Model'']/@package

java – VTD-XML大数据xPathExpression不使用名称空间

java – VTD-XML大数据xPathExpression不使用名称空间

在运行命名空间时,我有一个小的测试文件.如果我删除命名空间这两项工作我是否在使用巨大的代码做错了什么?

更改为删除不可行的代码

try {
        //without namespace works
        VTDGen vtdGen = new VTDGen();
        vtdGen.parseFile("test.xml",false);
        VTDNav vtdNav = vtdGen.getNav();
        Autopilot autopilot = new Autopilot(vtdNav);
        autopilot.selectXPath("//Receiver/Identifier");
        autopilot.evalXPath();
        System.out.println("Stand===>" + vtdNav.getXPathStringVal() + " ===>");
    } catch(indexoutofboundsexception e) {
        e.printstacktrace();
    }

    try {
        //with namespace doesn't work
        VTDGen vtdGen = new VTDGen();
        vtdGen.parseFile("test.xml",true);
        VTDNav vtdNav = vtdGen.getNav();
        Autopilot autopilot = new Autopilot(vtdNav);
        autopilot.declareXPathNameSpace("x","http://test/namespaces/ssfgf");
        autopilot.selectXPath("//x:Receiver/Identifier");
        int index = autopilot.evalXPath();
        System.out.println("Stand NS ===>" + vtdNav.toString(index) + " ===>");
    } catch(indexoutofboundsexception e) {
        e.printstacktrace();
    }

    try {
        //without namespace doesn't work
        VTDGenHuge vg = new VTDGenHuge();
        vg.parseFile("test.xml",false);
        VTDNavHuge vn = vg.getNav();
        AutopilotHuge ap = new AutopilotHuge(vn);
        ap.selectXPath("//Receiver/Identifier");
        ap.evalXPath();
        System.out.println("Huge ===> " + vn.toString(vn.getText()) + " ===>");
    } catch(indexoutofboundsexception e) {
        e.printstacktrace();
    }

    try {
        //with namespace doesn't work
        VTDGenHuge vg = new VTDGenHuge();
        vg.parseFile("test.xml",true);
        VTDNavHuge vn = vg.getNav();
        AutopilotHuge ap = new AutopilotHuge(vn);
        ap.declareXPathNameSpace("x","http://test/namespaces/ssfgf");
        ap.selectXPath("//Receiver/Identifier");
        ap.evalXPath();
        System.out.println("Huge NS ===> " + vn.toString(vn.getText()) + " ===>");
    } catch(indexoutofboundsexception e) {
        e.printstacktrace();
    }

我得到了巨大的代码和NS标准的java.lang.indexoutofboundsexception

这是一个样本XML,遗憾的是无法显示真正的xml

<x:TestDocument xmlns:x="http://test/namespaces/ssfgf" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://test/namespaces/ssfgf">
    <x:TestHeader>
        <x:Type></x:Type>
        <x:Scopes>
            <x:Scope>
                <x:Identifier>Context</x:Identifier>
                <x:Type>CaseId</x:Type>
                <x:InstanceIdentifier>case1</x:InstanceIdentifier>
                <x:Business>
                    <x:Name>businessnane1</x:Name>
                </x:Business>
            </x:Scope>
            <x:Scope>
                <x:Identifier>Context</x:Identifier>
                <x:InstanceIdentifier>test1</x:InstanceIdentifier>
                <x:Type>TestId</x:Type>
            </x:Scope>
            <x:Scope>
                <x:Identifier>Context</x:Identifier>
                <x:InstanceIdentifier>other1</x:InstanceIdentifier>
                <x:Type>OtherId</x:Type>
            </x:Scope>
        </x:Scopes>
        <x:Receiver>
            <x:Identifier>testreceiverid</x:Identifier>
        </x:Receiver>
        <x:DocumentIdentification>
            <x:Type>type1</x:Type>
            <x:Identifier>id1</x:Identifier>
            <x:TypeVersion>version1</x:TypeVersion>
        </x:DocumentIdentification>
    </x:TestHeader>
    <x:TestBody attribute1="attribute1" attribute2="attribute2">
        <TestingData>testingdata1</TestingData>
    </x:TestBody>
</x:TestDocument>

解决方法

由于一些问题,您将获得异常:一些使用您的代码,另一些使用扩展的VTD-xml.

首先,你没有使用VTD的第二个代码片段来启用命名空间感知.

您也没有设置名称空间绑定权限..

ap.declareXPathNameSpace("x","http://test/namespaces/ssfgf");

第三,getText()返回-1,这导致异常.

最后,// test将不匹配任何节点…所以getText()肯定会返回-1.

java – 使用XmlPullParser处理Xml名称空间

java – 使用XmlPullParser处理Xml名称空间

这里我使用XmlPullParser来解析下面的文档.由于命名空间,它不起作用,我如何解析命名空间?

XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(true);
XmlPullParser xpp = factory.newPullParser();

xpp.setInput(in, HTTP.UTF_8);
String namespace = xpp.getNamespace();

boolean inMessage = false;

int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
    //START TAGS
    if(eventType == XmlPullParser.START_TAG) {
        if(xpp.getName().equals(namespace+"resource")) {
            httpCode = Integer.valueOf( xpp.getAttributeValue(null, "code").trim() );
            type = xpp.getAttributeValue(null, "type").trim();
        } else if(xpp.getName().equals(namespace+"message")) {
            inMessage = true;
        }
    //TAG TEXT
    } else if(eventType == XmlPullParser.TEXT) {
        if(inMessage) {
            message = xpp.getText().trim();
            break; //CANCEL the iteration
        }
    } else if(eventType == XmlPullParser.END_TAG) {
        if(inMessage) {
            inMessage = false;
        }
    }
    eventType = xpp.next();
}

这是我要解析的文档类型的示例

<?xml version="1.0" encoding="UTF-8"?>
    <res:resource 
        xmlns:res="http://www.example.com/ns/server/resource"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://www.example.com/ns/server/resource resource.xsd "
        version="1" >
    <res:message httpCode="200" type="ok" >
        <![CDATA[Sample Success Response]]>
    </res:message>
    <dif:person 
        xmlns:dif="http://www.example.com/ns/server/resource"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://www.example.com/ns/server/person person.xsd "
        version="1" >
        <dif:name>test name</dif:name>
        <dif:description lang="en">test description</dif:description>
    </dif:person >
</res:resource>

我想分别解析res和dif.

解决方法:

您可以通过调用getPrefix方法来区分它们.一些测试代码:

try {
        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
        factory.setNamespaceAware(true);
        XmlPullParser parser = factory.newPullParser();                     
        InputStream input = getResources().openRawResource(R.raw.test);
        parser.setInput(input, HTTP.UTF_8);     
        int eventType = parser.getEventType();
        while(eventType != XmlPullParser.END_DOCUMENT){             
            if(eventType == XmlPullParser.START_TAG){ 
                String prefix = parser.getPrefix();
                String name   = parser.getName();
                Log.i("XML", String.format("prefix=%s,name=%s",prefix,name));
                if( "dif".equals(prefix)){
                    handleDiff(parser);
                }else if ("res".equals(prefix)){
                    handleRes(parser);
                }
            }

            eventType = parser.next();
        }
    } catch (Exception e) {
        Log.e("XML","",e);
    }  

Logcat输出你的测试数据:

prefix=res,name=resource  
prefix=res,name=message  
prefix=dif,name=person  
prefix=dif,name=name  
prefix=dif,name=description  

今天关于如何使用XPath在Java中使用名称空间查询XML?xpath 命名空间的讲解已经结束,谢谢您的阅读,如果想了解更多关于Java XML使用方法-使用xpath在XML文件中的节点列表中查找和添加/替换更多子节点、Java XPath:使用默认名称空间xmlns的查询、java – VTD-XML大数据xPathExpression不使用名称空间、java – 使用XmlPullParser处理Xml名称空间的相关知识,请在本站搜索。

本文标签: