使用 Java XPath 解析 XML 简单字符串
Posted
技术标签:
【中文标题】使用 Java XPath 解析 XML 简单字符串【英文标题】:Parse XML Simple String using Java XPath 【发布时间】:2013-05-18 17:20:02 【问题描述】:我有这样的 XML 字符串
<resp><status>good</status><msg>hi</msg></resp>
我遵循此帮助
Simplest way to query XML in Java
我的代码:
public static void main(String args[])
String xml = "<resp><status>good</status><msg>hi</msg></resp>";
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
InputSource source = new InputSource(new StringReader(xml));
String status = "";
String msg = "";
try
status = (String) xpath.evaluate("/resp/status", source,XPathConstants.STRING);
msg = (String) xpath.evaluate("/resp/msg", source,XPathConstants.STRING);
catch (Exception e)
e.printStackTrace();
System.out.println("status=" + status);
System.out.println("Message=" + msg);
我想获取 msg 节点值但我遇到了异常
java.io.IOException: Stream closed
at java.io.StringReader.ensureOpen(StringReader.java:39)
at java.io.StringReader.read(StringReader.java:73)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(XMLEntityScanner.java:1742)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.arrangeCapacity(XMLEntityScanner.java:1619)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.skipString(XMLEntityScanner.java:1657)
at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:193)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:771)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:107)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:225)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:283)
at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.evaluate(XPathImpl.java:468)
at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.evaluate(XPathImpl.java:515)
at Parsing.main(Parsing.java:25)--------------- linked to ------------------
javax.xml.xpath.XPathExpressionException
at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.evaluate(XPathImpl.java:475)
at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.evaluate(XPathImpl.java:515)
at Parsing.main(Parsing.java:25)
Caused by: java.io.IOException: Stream closed
at java.io.StringReader.ensureOpen(StringReader.java:39)
at java.io.StringReader.read(StringReader.java:73)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(XMLEntityScanner.java:1742)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.arrangeCapacity(XMLEntityScanner.java:1619)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.skipString(XMLEntityScanner.java:1657)
at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:193)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:771)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:107)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:225)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:283)
at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.evaluate(XPathImpl.java:468)
... 2 more
我不会为这个简单的任务使用一些外部库。请指导我如何获取其他节点的值。 谢谢
【问题讨论】:
如果您需要帮助,请发布您的所有方法... 不要指望只分享一行代码就能得到太多帮助。 【参考方案1】:您不能将相同的InputSource
重复用于多个evaluate()
调用,因为它会自动关闭。因此,您将收到 Stream closed
IO 异常。试试这个
InputSource source1 = new InputSource(new StringReader(xml));
InputSource source2 = new InputSource(new StringReader(xml));
String msg = xpath.evaluate("/resp/msg", source);
String status = xpath.evaluate("/resp/status", source2);
System.out.println("msg=" + msg + ";" + "status=" + status);
编辑:
更好的方法是使用 DocumentBuilderFactory
解析您的 XML 并首先构建一个 Document
(使用 JAXP 的 DOM API),然后可以在多个 XPath 评估中重用它。
String xml = "<resp><status>good</status><msg>hi</msg></resp>";
InputSource source = new InputSource(new StringReader(xml));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(source);
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
String msg = xpath.evaluate("/resp/msg", document);
String status = xpath.evaluate("/resp/status", document);
System.out.println("msg=" + msg + ";" + "status=" + status);
【讨论】:
所以如果我有很多节点,那么我必须为每个节点创建源代码?有没有更好的解决方案? 使用DocumentBuilderFactory
构建一个Document
(JAXP DOM API 的一部分),可以在多个 Xpath 评估中重复使用。【参考方案2】:
Ravi's solution也可以表示为:
String xml = "<resp><status>good</status><msg>hi</msg></resp>";
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
InputSource source = new InputSource(new StringReader(xml));
Document doc = (Document) xpath.evaluate("/", source, XPathConstants.NODE);
String status = xpath.evaluate("/resp/status", doc);
String msg = xpath.evaluate("/resp/msg", doc);
System.out.println("status=" + status);
System.out.println("Message=" + msg);
【讨论】:
出于兴趣,如果 XML 字符串是你可以试试jcabi-xml
,它在后台进行 DOM 操作:
import com.jcabi.xml.XML;
import com.jcabi.xml.XMLDocument;
XML xml = new XMLDocument("<resp>...</resp>");
String status = xml.xpath("/resp/status/text()").get(0);
【讨论】:
这个库很好,但我不喜欢的是它带来了 aspectj——我认为这不是真的必要 是的,我们计划很快摆脱它 那就太好了!我可以订阅任何 RSS 以使自己保持最新状态? @AlexeyGrigorev 关注/观看这张票:github.com/jcabi/jcabi-xml/issues/61以上是关于使用 Java XPath 解析 XML 简单字符串的主要内容,如果未能解决你的问题,请参考以下文章
Java DocumentBuilderFactory(javax.xml)通过XPath解析xml文件