当前位置: 首页 > 面试题库 >

XPath,XML命名空间和Java

东郭瀚玥
2023-03-14
问题内容

我花了整整一天的时间尝试从以下文档中提取一个XML节点,并且无法掌握XML命名空间的细微差别以使其正常工作。

XML文件总的来说很大,所以这是与我有关的部分:

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<XFDL xmlns="http://www.PureEdge.com/XFDL/6.5" xmlns:custom="http://www.PureEdge.com/XFDL/Custom" xmlns:designer="http://www.PureEdge.com/Designer/6.1" xmlns:pecs="http://www.PureEdge.com/PECustomerService" xmlns:xfdl="http://www.PureEdge.com/XFDL/6.5">
   <globalpage sid="global">
      <global sid="global">
         <xmlmodel xmlns:xforms="http://www.w3.org/2003/xforms">
            <instances>
               <xforms:instance id="metadata">
                  <form_metadata>
                     <metadataver version="1.0"/>
                     <metadataverdate>
                        <date day="05" month="Jul" year="2005"/>
                     </metadataverdate>
                     <title>
                        <documentnbr number="2062" prefix.army="DA" scope="army" suffix=""/>
                        <longtitle>HAND RECEIPT/ANNEX NUMBER </longtitle>
                     </title>

该文档继续进行,并且从头到尾都井井有条。我正在尝试从“ documentnbr”标签(底部的三个)中提取“ number”属性。

我用于执行此操作的代码如下所示:

/***
     * Locates the Document Number information in the file and returns the form number.
     * @return File's self-declared number.
     * @throws InvalidFormException Thrown when XPath cannot find the "documentnbr" element in the file.
     */
    public String getFormNumber() throws InvalidFormException
    {
        try{
            XPath xPath = XPathFactory.newInstance().newXPath();
            xPath.setNamespaceContext(new XFDLNamespaceContext());

            Node result = (Node)xPath.evaluate(QUERY_FORM_NUMBER, doc, XPathConstants.NODE);
            if(result != null) {
                return result.getNodeValue();
            } else {
                throw new InvalidFormException("Unable to identify form.");
            }

        } catch (XPathExpressionException err) {
            throw new InvalidFormException("Unable to find form number in file.");
        }

    }

其中QUERY_FORM_NUMBER是我的XPath表达式,而XFDLNamespaceContext实现NamespaceContext,如下所示:

public class XFDLNamespaceContext implements NamespaceContext {

    @Override
    public String getNamespaceURI(String prefix) {
        if (prefix == null) throw new NullPointerException("Invalid Namespace Prefix");
        else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX))
            return "http://www.PureEdge.com/XFDL/6.5";
        else if ("custom".equals(prefix))
            return "http://www.PureEdge.com/XFDL/Custom";
        else if ("designer".equals(prefix)) 
            return "http://www.PureEdge.com/Designer/6.1";
        else if ("pecs".equals(prefix)) 
            return "http://www.PureEdge.com/PECustomerService";
        else if ("xfdl".equals(prefix))
            return "http://www.PureEdge.com/XFDL/6.5";      
        else if ("xforms".equals(prefix)) 
            return "http://www.w3.org/2003/xforms";
        else    
            return XMLConstants.NULL_NS_URI;
    }

    @Override
    public String getPrefix(String arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Iterator getPrefixes(String arg0) {
        // TODO Auto-generated method stub
        return null;
    }

}

我已经尝试了许多不同的XPath查询,但是我一直感觉这样应该可行:

protected static final String QUERY_FORM_NUMBER = 
        "/globalpage/global/xmlmodel/xforms:instances/instance" + 
        "/form_metadata/title/documentnbr[number]";

不幸的是,它不起作用,并且我不断得到null回报。

在这里,这里和这里,我已经做了大量的阅读,但是事实证明,没有什么能帮助我完成这项工作的。

当我弄清楚这一点时,我几乎可以肯定我将面对面的掌控,但是对于我所缺少的东西,我真的很机智。

感谢您阅读所有这些内容,并预先感谢您的帮助。

-安迪


问题答案:

啊哈,我尝试调试您的表达式+使它起作用。你错过了几件事。这个XPath表达式应该做到这一点:

/XFDL/globalpage/global/xmlmodel/instances/instance/form_metadata/title/documentnbr/@number
  1. 您需要包括根元素(在这种情况下为XFDL)
  2. 由于某种原因,我最终不需要在表达式中使用任何名称空间。不知道为什么。如果是这种情况,则永远不会调用NamespaceContext.getNamespaceURI()。如果我替换instancexforms:instancegetNamespaceURI(),则将其xforms作为输入参数调用一次,但是程序将引发异常
  3. 属性值的语法@attr不是[attr]

我完整的示例代码:

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpresshtml" target="_blank">ionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

public class XPathNamespaceExample {
    static public class MyNamespaceContext implements NamespaceContext {
        final private Map<String, String> prefixMap;
        MyNamespaceContext(Map<String, String> prefixMap)
        {
            if (prefixMap != null)
            {
                this.prefixMap = Collections.unmodifiableMap(new HashMap<String, String>(prefixMap));
            }
            else
            {
                this.prefixMap = Collections.emptyMap();
            }
        }
        public String getPrefix(String namespaceURI) {
            // TODO Auto-generated method stub
            return null;
        }
        public Iterator getPrefixes(String namespaceURI) {
            // TODO Auto-generated method stub
            return null;
        }
        public String getNamespaceURI(String prefix) {
                if (prefix == null) throw new NullPointerException("Invalid Namespace Prefix");
                else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX))
                    return "http://www.PureEdge.com/XFDL/6.5";
                else if ("custom".equals(prefix))
                    return "http://www.PureEdge.com/XFDL/Custom";
                else if ("designer".equals(prefix)) 
                    return "http://www.PureEdge.com/Designer/6.1";
                else if ("pecs".equals(prefix)) 
                    return "http://www.PureEdge.com/PECustomerService";
                else if ("xfdl".equals(prefix))
                    return "http://www.PureEdge.com/XFDL/6.5";      
                else if ("xforms".equals(prefix)) 
                    return "http://www.w3.org/2003/xforms";
                else    
                    return XMLConstants.NULL_NS_URI;
        }


    }

    protected static final String QUERY_FORM_NUMBER = 
        "/XFDL/globalpage/global/xmlmodel/xforms:instances/instance" + 
        "/form_metadata/title/documentnbr[number]";

    public static void main(String[] args) {
        try
        {
            DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
            Document doc = docBuilder.parse(new File(args[0]));
            System.out.println(extractNodeValue(doc, "/XFDL/globalpage/@sid"));
            System.out.println(extractNodeValue(doc, "/XFDL/globalpage/global/xmlmodel/instances/instance/@id" ));
            System.out.println(extractNodeValue(doc, "/XFDL/globalpage/global/xmlmodel/instances/instance/form_metadata/title/documentnbr/@number" ));
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
    }

    private static String extractNodeValue(Document doc, String expression) {
        try{

            XPath xPath = XPathFactory.newInstance().newXPath();
            xPath.setNamespaceContext(new MyNamespaceContext(null));

            Node result = (Node)xPath.evaluate(expression, doc, XPathConstants.NODE);
            if(result != null) {
                return result.getNodeValue();
            } else {
                throw new RuntimeException("can't find expression");
            }

        } catch (XPathExpressionException err) {
            throw new RuntimeException(err);
        }
    }
}


 类似资料:
  • XPath如何处理XML命名空间? 如果我使用 为了解析下面的XML文档,我得到了0个节点。 但是,我没有在XPath中指定名称空间(即不是路径的每个标记的前缀)。如果我没有明确告诉XPath,它怎么知道我想要哪个?我认为在这种情况下(因为只有一个名称空间),XPath可以完全忽略。但如果有多个名称空间,事情可能会变得糟糕。

  • 主要内容:命名冲突,使用前缀来避免命名冲突,XML 命名空间 - xmlns 属性,统一资源标识符(URI,全称 Uniform Resource Identifier),默认的命名空间,实际使用中的命名空间XML 命名空间提供避免元素命名冲突的方法。 命名冲突 在 XML 中,元素名称是由开发者定义的,当两个不同的文档使用相同的元素名时,就会发生命名冲突。 这个 XML 携带 HTML 表格的信息: <table> <tr> <td>Apples</td> <td>Bananas</td> <

  • 供应商提供的XML如下: 请注意,没有声明,供应商也没有提供模式。这不能更改,供应商将来会继续这样发布XML。 为了生成JAXB绑定,我创建了如下模式: 请注意,我已经声明了一个或多或少有意义的命名空间(“http://acme.com/schema”),以便它可以用于元素引用等。XJC 生成以下: 然后,我尝试解组XML文档: 我得到的例外是: 显然,这是因为XML元素属于一个空的名称空间,而J

  • 问题内容: 我想使用JDOM读取XML文件,然后使用XPath从JDOM Document中提取数据。它可以很好地创建Document对象,但是当我使用XPath在Document中查询元素列表时,我什么也没得到。 我的XML文档在根元素中定义了一个默认名称空间。有趣的是,当我删除默认名称空间时,它成功运行了XPath查询并返回了我想要的元素。要使XPath查询返回结果,我还必须做什么? XML:

  • 本文向大家介绍xpath 示例XML(无名称空间),包括了xpath 示例XML(无名称空间)的使用技巧和注意事项,需要的朋友参考一下 示例 这是一些示例XML,可以针对这些XML编写示例XPath:            

  • XML信封命名空间的正确URI是什么。我见过很多,例如。”http://www.w3.org/2001/12/soap-envelope“,”http://www.w3.org/2001/06/soap-envelope“,”http://www.w3.org/2003/05/soap-envelope“,”http://schemas.xmlsoap.org/soap/envelope/“。请告