使用Java SAX解析器时如何在循环外访问节点
SAX解析XML后在循环外部访问节点的方法
问题描述
我已经用Java的SAX解析器解析XML文档,通过继承DefaultHandler类并实现startElement、endElement和characters方法,成功打印出所有节点值。现在想了解如何在遍历员工列表的for循环外部访问这些节点数据。
示例XML
<Employees> <Employee id="1"> <age>29</age> <name>Pankaj</name> <gender>Male</gender> <role>Java Developer</role> </Employee> <Employee id="2"> <age>35</age> <name>Lisa</name> <gender>Female</gender> <role>CEO</role> </Employee> </Employees>
Java解析代码
public class XMLParserSAX { public static void main(String[] args) { SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); try { SAXParser saxParser = saxParserFactory.newSAXParser(); MyHandler handler = new MyHandler(); saxParser.parse(new File("/Users/yashvanth/IdeaProjects/parsing/src/staff.xml"), handler); List<Employee> empList = handler.getEmpList(); for(Employee emp : empList) System.out.println(emp); // 可在此处的for循环外部访问empList中的节点数据 } catch (ParserConfigurationException | SAXException | IOException e) { e.printStackTrace(); } } }
Handler类代码
public class MyHandler extends DefaultHandler { private List<Employee> empList = null; private Employee emp = null; private StringBuilder data = null; public List<Employee> getEmpList() { return empList; } boolean bAge = false; boolean bName = false; boolean bGender = false; boolean bRole = false; @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equalsIgnoreCase("Employee")) { String id = attributes.getValue("id"); emp = new Employee(); emp.setId(Integer.parseInt(id)); if (empList == null) empList = new ArrayList<>(); } else if (qName.equalsIgnoreCase("name")) { bName = true; } else if (qName.equalsIgnoreCase("age")) { bAge = true; } else if (qName.equalsIgnoreCase("gender")) { bGender = true; } else if (qName.equalsIgnoreCase("role")) { bRole = true; } data = new StringBuilder(); } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (bAge) { emp.setAge(Integer.parseInt(data.toString())); bAge = false; } else if (bName) { emp.setName(data.toString()); bName = false; } else if (bRole) { emp.setRole(data.toString()); bRole = false; } else if (bGender) { emp.setGender(data.toString()); bGender = false; } if (qName.equalsIgnoreCase("Employee")) { empList.add(emp); } } @Override public void characters(char ch[], int start, int length) throws SAXException { data.append(new String(ch, start, length)); } }
当前输出
Employee:: ID=1 Name=Pankaj Age=29 Gender=Male Role=Java Developer Employee:: ID=2 Name=Lisa Age=35 Gender=Female Role=CEO
解决方案
你已经通过handler.getEmpList()获取到了存储所有员工节点的List<Employee>集合,这个集合完全可以在for循环外部直接使用,常见的访问方式包括:
获取指定位置的员工节点:
// 获取第一个员工 Employee firstEmployee = empList.get(0); System.out.println("第一个员工姓名:" + firstEmployee.getName());根据ID查找特定员工:
// 查找ID为2的员工 Employee targetEmp = empList.stream() .filter(emp -> emp.getId() == 2) .findFirst() .orElse(null); if(targetEmp != null){ System.out.println("ID为2的员工职位:" + targetEmp.getRole()); }将集合传递给其他方法处理:
// 把员工列表传给业务方法做后续处理 processEmployeeData(empList);转换为Map方便快速查找:
// 转成以ID为key的Map,后续可快速查找 Map<Integer, Employee> empMap = empList.stream() .collect(Collectors.toMap(Employee::getId, emp -> emp)); // 直接通过ID获取员工 Employee emp = empMap.get(1);
本质上,empList是解析完成后在内存中存储的完整员工数据集合,只要变量作用域允许,你可以在解析完成后的任何地方直接操作这个集合,无需局限在遍历的for循环内部。
内容的提问来源于stack exchange,提问作者user2628187
相关产品推荐
相关产品推荐

