Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
XPath、XML名称空间和Java_Java_Xpath_Xml Namespaces_Xfdl - Fatal编程技术网

XPath、XML名称空间和Java

XPath、XML名称空间和Java,java,xpath,xml-namespaces,xfdl,Java,Xpath,Xml Namespaces,Xfdl,我花了一天的时间试图从下面的文档中提取出一个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"

我花了一天的时间试图从下面的文档中提取出一个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>
其中QUERY_FORM_NUMBER是我的XPath表达式,XFDLNamespaceContext实现NamespaceContext,如下所示:

/***
     * 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.");
        }

    }
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]";
不幸的是,它不起作用,我不断得到一个空返回

我已经读了相当多的书,但是没有什么能充分说明我的工作

我几乎可以肯定,当我明白这一点的时候,我会直面现实,但我真的不知道我错过了什么

感谢您通读所有这些内容,并提前感谢您的帮助


-安迪

啊哈,我试着调试你的表情,让它起作用了。你错过了一些东西。此XPath表达式应该完成以下操作:

/XFDL/globalpage/global/xmlmodel/instances/instance/form_metadata/title/documentnbr/@number
  • 您需要包含根元素(本例中为XFDL)
  • 出于某种原因,我最终不需要在表达式中使用任何名称空间。不知道为什么。如果是这种情况,则永远不会调用NamespaceContext.getNamespaceURI()。如果我将
    instance
    替换为
    xforms:instance
    ,则会使用
    xforms
    作为输入参数调用getNamespaceURI(),但程序会引发异常
  • 属性值的语法是
    @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.XPathExpressionException;
    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 xpath = XPathFactory.newInstance().newXPath();
    
    NamespaceContextMap contextMap = new NamespaceContextMap();
    contextMap.put("custom", "http://www.PureEdge.com/XFDL/Custom");
    contextMap.put("designer", "http://www.PureEdge.com/Designer/6.1");
    contextMap.put("pecs", "http://www.PureEdge.com/PECustomerService");
    contextMap.put("xfdl", "http://www.PureEdge.com/XFDL/6.5");
    contextMap.put("xforms", "http://www.w3.org/2003/xforms");
    contextMap.put("", "http://www.PureEdge.com/XFDL/6.5");
    
    xpath.setNamespaceContext(contextMap);
    String expression = "//:documentnbr/@number";
    InputSource inputSource = new InputSource("input.xml");
    String number;
    number = (String) xpath.evaluate(expression, inputSource, XPathConstants.STRING);
    System.out.println(number);
    
    导入java.io.File;
    导入java.io.IOException;
    导入java.util.Collections;
    导入java.util.HashMap;
    导入java.util.Iterator;
    导入java.util.Map;
    导入javax.xml.xmlstants;
    导入javax.xml.namespace.NamespaceContext;
    导入javax.xml.parsers.DocumentBuilder;
    导入javax.xml.parsers.DocumentBuilderFactory;
    导入javax.xml.parsers.parserConfiguration异常;
    导入javax.xml.xpath.xpath;
    导入javax.xml.xpath.XPathConstants;
    导入javax.xml.xpath.XPathExpressionException;
    导入javax.xml.xpath.XPathFactory;
    导入org.w3c.dom.Document;
    导入org.w3c.dom.Node;
    导入org.xml.sax.SAXException;
    公共类XPathNamespaceExample{
    静态公共类MyNamespaceContext实现NamespaceContext{
    最终私有映射前缀映射;
    MyNamespaceContext(映射前缀映射)
    {
    if(prefixMap!=null)
    {
    this.prefixMap=Collections.unmodifiableMap(新HashMap(prefixMap));
    }
    其他的
    {
    this.prefixMap=Collections.emptyMap();
    }
    }
    公共字符串getPrefix(字符串名称空间URI){
    //TODO自动生成的方法存根
    返回null;
    }
    公共迭代器getPrefixes(字符串名称空间URI){
    //TODO自动生成的方法存根
    返回null;
    }
    公共字符串getNamespaceURI(字符串前缀){
    if(prefix==null)抛出新的NullPointerException(“无效的命名空间前缀”);
    else if(前缀.equals(XMLConstants.DEFAULT\u NS\u前缀))
    返回“http://www.PureEdge.com/XFDL/6.5";
    else if(“自定义”。等于(前缀))
    返回“http://www.PureEdge.com/XFDL/Custom";
    else if(“designer”.equals(前缀))
    返回“http://www.PureEdge.com/Designer/6.1";
    else if(“pecs.”等于(前缀))
    返回“http://www.PureEdge.com/PECustomerService";
    else if(“xfdl”.equals(前缀))
    返回“http://www.PureEdge.com/XFDL/6.5";      
    else if(“xforms”.equals(前缀))
    返回“http://www.w3.org/2003/xforms";
    其他的
    返回XMLConstants.NULL\u NS\u URI;
    }
    }
    受保护的静态最终字符串查询\u表单\u编号=
    “/XFDL/globalpage/global/xmlmodel/xforms:instances/instance”+
    “/form_metadata/title/documentnbr[编号]”;
    公共静态void main(字符串[]args){
    尝试
    {
    DocumentBuilderFactory dbfac=DocumentBuilderFactory.newInstance();
    DocumentBuilder docBuilder=dbfac.newDocumentBuilder();
    Document doc=docBuilder.parse(新文件(args[0]);
    System.out.println(extractNodeValue(doc,“/XFDL/globalpage/@sid”);
    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”);
    }捕获(SAXE异常){
    e、 printStackTrace();
    }捕获(IOE异常){
    e、 printStackTrace();
    }捕获(ParserConfiguration异常e){
    e、 printStackTrace();
    }
    }
    私有静态字符串extractNodeValue(文档文档,字符串表达式){
    试一试{
    XPath=XPathFactory.newInstance().newXPath();
    setNamespaceContext(新的MyNamespaceContext(null));
    节点结果=(节点)xPath.evaluate(表达式、文档、XPathConstants.Node);
    如果(结果!=null){
    返回result.getNodeValue();
    }否则{
    抛出新的RuntimeException(“找不到表达式”);
    }
    }捕获(XPathExpressionException错误){
    抛出新的运行时异常(err);
    }
    }
    }
    
    SAX(XPath的替代品)版本:

    我认为将XPath与名称空间结合使用会更加复杂,因为它应该是(我的观点)。以下是我的(简单)代码:

    您可以从(GPL许可证)获取NamespaceContextMap类(不是我的)。还有一个bug。

    看看这个库。这是一种更简单的使用XPath的方法,而不会与低级Java API发生冲突,
    XPath xpath = XPathFactory.newInstance().newXPath();
    
    NamespaceContextMap contextMap = new NamespaceContextMap();
    contextMap.put("custom", "http://www.PureEdge.com/XFDL/Custom");
    contextMap.put("designer", "http://www.PureEdge.com/Designer/6.1");
    contextMap.put("pecs", "http://www.PureEdge.com/PECustomerService");
    contextMap.put("xfdl", "http://www.PureEdge.com/XFDL/6.5");
    contextMap.put("xforms", "http://www.w3.org/2003/xforms");
    contextMap.put("", "http://www.PureEdge.com/XFDL/6.5");
    
    xpath.setNamespaceContext(contextMap);
    String expression = "//:documentnbr/@number";
    InputSource inputSource = new InputSource("input.xml");
    String number;
    number = (String) xpath.evaluate(expression, inputSource, XPathConstants.STRING);
    System.out.println(number);
    
    String num = XPathAPI.selectSingleNodeAsString(doc, '//documentnbr/@number');
    
    Map<String, String> nsMap = new HashMap<String, String>();
    nsMap.put("xforms", "http://www.w3.org/2003/xforms");
    
    String num =
        XPathAPI.selectSingleNodeAsString(doc, '//documentnbr/@number', nsMap);