【问题标题】:Parsing xml using Java使用 Java 解析 xml
【发布时间】:2012-01-30 05:42:36
【问题描述】:

我正在尝试解析一个 dom 元素。

元素元素:

<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>http://X/feed2</id>
  <title>Sample Feed</title>
  <entry>
    <id>http://X/feed2/104</id>
    <title>New Title</title>
  </entry>
</feed>

我正在尝试获取以下条目:

<entry>
  <id>http://top.cs.vt.edu/libx2/vsony7@vt.edu/feed2/104</id>
  <title>New Title</title>
</entry>

我正在使用 xpath 解析 xml:

"/atom:feed/atom:entry[atom:id=\"http://X/feed2/104\"]"

但是,当我尝试解析 Dom 元素时出现异常。有人可以建议一种简单的方法来在 Java 中实现这一点吗?

请看我的完整代码:

public static parseXml() {
        String externalEntryIdUrl = "http://theta.cs.vt.edu/~rupen/thirtylibapps/137";
        String externalFeedUrl = StringUtils.substringBeforeLast(externalEntryIdUrl, "/");
        try {
            URL url = new URL(externalFeedUrl);
            InputStream externalXml = new BufferedInputStream(url.openStream());
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(externalXml);
            Element externalFeed = doc.getDocumentElement();
            String atomNameSpace = "xmlns:atom=\"http://www.w3.org/2005/Atom\"";
            String entryIdPath = String.format("//%s:entry[%s:id=%s]", atomNameSpace, atomNameSpace, externalEntryIdUrl);
            Element externalEntry = (Element) XPathSupport.evalNode(entryIdPath, externalFeed);
        } catch (Exception ex) {
            // Throw exception
        }
    }

static synchronized Node evalNode(String xpathExpr, Node node) {
    NodeList result = evalNodeSet(xpathExpr, node);
    if (result.getLength() > 1)
        throw new Error ("More than one node for:" + xpathExpr);
    else if (result.getLength() == 1)
        return result.item(0);
    else
        return null;
}

static synchronized NodeList evalNodeSet(String xpathExpr, Node node) {
        try {
                static XPath xpath = factory.newXPath();
                xpath.setNamespaceContext(context);

                static NamespaceContext context = new NamespaceContext() {
                    private Map<String, String> prefix2URI = new HashMap<String, String>();
                    {
                        prefix2URI.put("libx", "http://libx.org/xml/libx2");
                        prefix2URI.put("atom", "http://www.w3.org/2005/Atom");
                    }
                };

            XPathExpression expr = xpath.compile(xpathExpr);
            Object result = expr.evaluate(node, XPathConstants.NODESET);
            return (NodeList)result;
        } catch (XPathExpressionException xpee) {
            throw new Error ("An xpath expression exception: " + xpee);
        }
    }

严重:>>java.lang.Error:一个 xpath 表达式异常:javax.xml.xpath.XPathExpressionException

【问题讨论】:

  • “我得到一个例外” 那是TooManyKittensException 吗?对汤姆猫进行绝育。还有什么?也许您可以与我们分享(即复制/粘贴)。
  • 您是否在 Java 代码中将前缀 atom 关联(注册了命名空间)到命名空间 "http://www.w3.org/2005/Atom"?您必须这样做(推荐)或使用类似:/*/*[local-name() = 'entry'][*[local-name() = 'id'] = 'http://X/feed2/104]'

标签: java xml dom xpath


【解决方案1】:

您可以使用 SAX 解析器。 这里是一个 SAX 解析的例子http://www.mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/

【讨论】:

    【解决方案2】:

    您可以利用 NamespaceContext 并执行以下操作:

    package forum9059851;
    
    import java.io.FileInputStream;
    import java.util.Iterator;
    import javax.xml.namespace.NamespaceContext;
    import javax.xml.xpath.*;
    import org.w3c.dom.Element;
    import org.xml.sax.InputSource;
    
    public class Demo {
    
        public static void main(String[] args) {
            try {
                XPathFactory xpf = XPathFactory.newInstance();
                XPath xp = xpf.newXPath();
                xp.setNamespaceContext(new MyNamespaceContext());
                XPathExpression xpe = xp.compile("ns:feed/ns:entry");
                FileInputStream xmlStream = new FileInputStream("src/forum9059851/input.xml");
                InputSource xmlInput = new InputSource(xmlStream);
                Element result = (Element) xpe.evaluate(xmlInput, XPathConstants.NODE);
                System.out.println(result);
            } catch (Exception ex) {
                // Throw exception
            }
        }
    
        private static class MyNamespaceContext implements NamespaceContext {
    
            public String getNamespaceURI(String prefix) {
                if("ns".equals(prefix)) {
                    return "http://www.w3.org/2005/Atom";
                }
                return null;
            }
    
            public String getPrefix(String namespaceURI) {
                return null;
            }
    
            public Iterator getPrefixes(String namespaceURI) {
                return null;
            }
    
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      如果您不想重新发明轮子并想解析提要数据,我建议您使用已经可用的 Rome 库。

      【讨论】:

        【解决方案4】:

        我发现我在从 URL 获取 xml 时没有设置命名空间感知。

        所以,

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        

        这样做可以解决我的问题。如果不这样做,在解析 xml 时为 XPathFactory 实例设置命名空间上下文(如我的示例所示)本身不起作用。

        【讨论】:

          猜你喜欢
          • 2017-12-07
          • 2012-11-18
          • 2012-01-10
          • 2014-02-24
          • 2013-12-24
          • 1970-01-01
          • 2013-01-22
          • 2013-02-20
          • 2018-01-04
          相关资源
          最近更新 更多