Java结合XPath:如何依据特定元素获取完整节点?
在Java中使用XPath获取指定的完整XML节点
没问题,我给你一步步拆解怎么用Java的XPath工具从你的学生XML里精准拿到想要的完整节点。先看你给出的XML结构,我们可以围绕「按学号找学生节点」「按姓名找对应的分数节点」这类常见需求来演示。
第一步:准备依赖与导入包
首先你需要用到Java自带的XML处理API,不需要额外引入第三方库,直接导入这些包:
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource;
第二步:解析XML文档
不管你的XML是来自文件、字符串还是网络流,首先得把它解析成org.w3c.dom.Document对象,这是后续操作的基础。这里以解析字符串为例:
public static Document parseXmlString(String xml) throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 关闭DTD验证,避免不必要的报错(如果你的XML没有DTD的话) factory.setValidating(false); factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); DocumentBuilder builder = factory.newDocumentBuilder(); return builder.parse(new InputSource(new StringReader(xml))); }
第三步:编写XPath表达式并执行
接下来就是核心的XPath操作了,先创建XPath实例,然后根据你的需求写表达式,最后执行获取节点。
示例1:按学号获取完整的节点
比如要拿学号为1的学生节点,XPath表达式可以写://student[@studentnumber='1']
public static void getStudentByNumber(Document doc) throws Exception { XPathFactory xPathFactory = XPathFactory.newInstance(); XPath xpath = xPathFactory.newXPath(); // 编写XPath表达式 String expression = "//student[@studentnumber='1']"; XPathExpression xPathExpr = xpath.compile(expression); // 执行表达式,获取单个Node Node studentNode = (Node) xPathExpr.evaluate(doc, XPathConstants.NODE); // 如果要输出这个节点的XML内容,可以写个辅助方法 if (studentNode != null) { System.out.println("找到的学生节点:"); System.out.println(nodeToString(studentNode)); } else { System.out.println("未找到对应节点"); } }
示例2:获取指定学生的节点
比如要找Charlie的分数节点,表达式可以是://student[firstname='Charlie']/marks
public static void getMarksByName(Document doc) throws Exception { XPath xpath = XPathFactory.newInstance().newXPath(); String expression = "//student[firstname='Charlie']/marks"; Node marksNode = (Node) xpath.evaluate(expression, doc, XPathConstants.NODE); if (marksNode != null) { System.out.println("Charlie的分数节点:"); System.out.println(nodeToString(marksNode)); } }
辅助方法:把Node转成字符串输出
上面用到的nodeToString方法可以这样实现,方便你查看拿到的节点内容:
import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.StringWriter; public static String nodeToString(Node node) throws Exception { StringWriter sw = new StringWriter(); TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); transformer.transform(new DOMSource(node), new StreamResult(sw)); return sw.toString(); }
一些注意事项
- 如果你的XML带有命名空间,那需要给XPath设置
NamespaceContext,否则表达式会找不到节点。 - 如果要匹配多个节点(比如所有分数第三科大于90的学生),可以用
XPathConstants.NODE_LIST返回NodeList,然后遍历处理。 - 记得捕获异常:
ParserConfigurationException、SAXException、IOException、XPathExpressionException这些都需要在代码里处理或者抛出。
完整测试代码
把所有部分整合起来,用你提供的XML做测试:
import java.io.StringReader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.InputSource; public class XPathXmlDemo { public static void main(String[] args) { // 你的XML内容 String xml = "<students>" + " <student studentnumber=\"1\">" + " <firstname>Charlie</firstname>" + " <lastname>Davies</lastname>" + " <marks>" + " <first>12</first>" + " <second>52</second>" + " <third>98</third>" + " <forth>32</forth>" + " </marks>" + " </student>" + " <student studentnumber=\"2\">" + " <firstname>Emily</firstname>" + " <lastname>Roberts</lastname>" + " <marks>" + " <first>55</first>" + " </marks>" + " </student>" + "</students>"; try { Document doc = parseXmlString(xml); getStudentByNumber(doc); getMarksByName(doc); } catch (Exception e) { e.printStackTrace(); } } // 解析XML字符串为Document public static Document parseXmlString(String xml) throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false); factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); DocumentBuilder builder = factory.newDocumentBuilder(); return builder.parse(new InputSource(new StringReader(xml))); } // 按学号获取学生节点 public static void getStudentByNumber(Document doc) throws Exception { XPath xpath = XPathFactory.newInstance().newXPath(); String expression = "//student[@studentnumber='1']"; Node studentNode = (Node) xpath.evaluate(expression, doc, XPathConstants.NODE); if (studentNode != null) { System.out.println("=== 学号为1的学生节点 ==="); System.out.println(nodeToString(studentNode)); } } // 按姓名获取分数节点 public static void getMarksByName(Document doc) throws Exception { XPath xpath = XPathFactory.newInstance().newXPath(); String expression = "//student[firstname='Charlie']/marks"; Node marksNode = (Node) xpath.evaluate(expression, doc, XPathConstants.NODE); if (marksNode != null) { System.out.println("\n=== Charlie的分数节点 ==="); System.out.println(nodeToString(marksNode)); } } // Node转字符串 public static String nodeToString(Node node) throws Exception { StringWriter sw = new StringWriter(); TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); transformer.transform(new DOMSource(node), new StreamResult(sw)); return sw.toString(); } }
运行这段代码,就能看到你想要的完整节点内容啦。
内容的提问来源于stack exchange,提问作者Tri Nguyen
相关产品推荐
相关产品推荐

