在Java中读取多级XML文件

在Java中读取多级XML文件,java,xml,Java,Xml,直到最近,我的XML文件的标记结构还相当简单。但是现在我有了一个额外级别的带有标记的标记,解析XML变得更加复杂 下面是我的新XML文件的一个示例(我更改了标记名以便于理解): 约翰 14 A. B A+ 汤姆 13 A. 残缺的 上面的XML的重要特性是,我可以有多个“课程”属性,其中我可以有任意命名的标记作为它们的子项。这些子元素可以有任意数量,我想读入“name”,“value”的HashMap 公共静态树映射getAllSchoolRosterInformation(字符串文件名){

直到最近,我的XML文件的标记结构还相当简单。但是现在我有了一个额外级别的带有标记的标记,解析XML变得更加复杂

下面是我的新XML文件的一个示例(我更改了标记名以便于理解):


约翰
14
A.
B
A+
汤姆
13
A.
残缺的
上面的XML的重要特性是,我可以有多个“课程”属性,其中我可以有任意命名的标记作为它们的子项。这些子元素可以有任意数量,我想读入“name”,“value”的HashMap

公共静态树映射getAllSchoolRosterInformation(字符串文件名){
TreeMap school花名册=新TreeMap();
试一试{
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
DocumentBuilder db=dbf.newDocumentBuilder();
文件=新文件(文件名);
if(file.exists()){
文档doc=db.parse(文件);
Element docEle=doc.getDocumentElement();
NodeList studentList=docEle.getElementsByTagName(“学生”);
if(studentList!=null&&studentList.getLength()>0){
对于(int i=0;i0){
课程[]课程=新课程[nodeList.getLength()];
对于(int j=0;j

我遇到的问题是,学生在“数学”中得的不是“A”,而是“数学”中得的是空。(如果这篇文章太长,我可以试着找到一些缩短它的方法。)

如果这是我的项目,我将避免尝试手动解析HTML中的数据,而是让Java使用JAXB为我完成。我越是使用这个工具,我就越喜欢它。我敦促您考虑尝试这个,因为如果您这样做,那么您需要将XML更改为java对象的所有内容都是java类中的正确注释,然后解析器XML。使用的代码会简单得多,因此出错的可能性也会小得多

例如,以下代码非常容易、干净地将信息编组为XML:

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement
public class SchoolRoster {
   @XmlElement(name = "student")
   private List<Student> students = new ArrayList<Student>();

   public SchoolRoster() {
   }

   public List<Student> getStudents() {
      return students;
   }

   public void addStudent(Student student) {
      students.add(student);
   }

   public static void main(String[] args) {
      Student john = new Student("John", 14);
      john.addCourse(new Course("math", "A"));
      john.addCourse(new Course("english", "B"));

      Student tom = new Student("Tom", 13);
      tom.addCourse(new Course("gym", "A"));
      tom.addCourse(new Course("geography", "incomplete"));

      SchoolRoster roster = new SchoolRoster();
      roster.addStudent(tom);
      roster.addStudent(john);

      try {
         JAXBContext context = JAXBContext.newInstance(SchoolRoster.class);
         Marshaller marshaller = context.createMarshaller();
         marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

         String pathname = "MySchoolRoster.xml";
         File rosterFile = new File(pathname );
         marshaller.marshal(roster, rosterFile);
         marshaller.marshal(roster, System.out);

      } catch (JAXBException e) {
         e.printStackTrace();
      }
   }
}

@XmlRootElement
@XmlType(propOrder = { "name", "age", "courses" })
class Student {
  // TODO: completion left as an exercise for the original poster
}

@XmlRootElement
@XmlType(propOrder = { "name", "grade" })
class Course {
  // TODO: completion left as an exercise for the original poster
}
toString()
方法添加到我的类后,这导致:

SchoolRoster 
  [students=
    [Student [name=Tom, age=13, courses=[Course [name=gym, grade=A], Course [name=geography, grade=incomplete]]], 
    Student [name=John, age=14, courses=[Course [name=math, grade=A], Course [name=english, grade=B]]]]]

请不要在生产代码中使用此选项。很难看。但它将为您指明正确的方向。

像@Hovercraft一样,我建议使用库来处理xml的序列化。我发现Xstream具有很好的性能和易用性。

例如:

public static void saveStudentsXML(FileOutputStream file) throws Exception {
    if (xstream == null)
        initXstream();

    xstream.toXML(proctorDAO.studentList, file);
    file.close(); 
 }

 public static void initXstream() {
    xstream = new XStream();
    xstream.alias("student", Student.class);

    xstream.useAttributeFor(Student.class, "lastName");
    xstream.useAttributeFor(Student.class, "firstName");
    xstream.useAttributeFor(Student.class, "id");
    xstream.useAttributeFor(Student.class, "gradYear");
    xstream.aliasAttribute(Student.class, "lastName", "last");
    xstream.aliasAttribute(Student.class, "gradYear", "gc");
    xstream.aliasAttribute(Student.class, "firstName", "first");
}
演示嵌套属性的示例XML:

<list>
  <student first="Ralf" last="Adams" gc="2014" id="100">
     <testingMods value="1" boolMod="2"/>
  </student>
  <student first="Mick" last="Agosti" gc="2014" id="102">
     <testingMods value="1" boolMod="2"/>
  </student>
  <student first="Edmund" last="Baggio" gc="2013" id="302">
     <testingMods value="1" boolMod="6"/>
  </student> 
</list>


我注意到您提供的XML有一个包含两个等级的课程元素:数学为A,英语为B。这准确吗?你的问题是只显示数学成绩,还是你有一个更一般的问题?@orzechowskid:是的,我觉得很有趣。如果是我的项目,我会有一个课程列表,并使用
作为标记,使用
作为子标记。这是准确的。我数学只需要一个A级。但是我可能有一长串的选项,每个选项都可能有几个类,比如“数学”。@theJollySin:它可能是“精确的”,但形式不好。JAXB(JSR-222)实际上是一个标准,有多个开源实现:Metro、MOXy(我是技术负责人),JDK中包含了一个实现,它是JAX-WS和JAX-RS的标准WebService绑定层。下面是与XStream的比较:这应该是对现有代码的快速更改,我假设可以通过对现有代码进行最小的更改来完成。如果这开始让一切变得丑陋,也许是时候重构了。今晚我来看看JAXB。好的,我喜欢你的解决方案。但是你为什么说它很丑呢?您是否同意气垫船和Thorn的观点,即我应该使用更好的库来解析XML文件?还是你认为有som
private static void unmarshallTest() {
  try {
     JAXBContext context = JAXBContext.newInstance(SchoolRoster.class);
     Unmarshaller unmarshaller = context.createUnmarshaller();

     String pathname = "MySchoolRoster.xml"; // whatever the file name should be
     File rosterFile = new File(pathname );
     SchoolRoster roster = (SchoolRoster) unmarshaller.unmarshal(rosterFile);
     System.out.println(roster);
  } catch (JAXBException e) {
     e.printStackTrace();
  }
}
SchoolRoster 
  [students=
    [Student [name=Tom, age=13, courses=[Course [name=gym, grade=A], Course [name=geography, grade=incomplete]]], 
    Student [name=John, age=14, courses=[Course [name=math, grade=A], Course [name=english, grade=B]]]]]
for (int k = 0; k < CourseNodeList.getLength(); k++) {
    if (CourseNodeList.item(k).getNodeType() == Node.ELEMENT_NODE && CourseNodeList != null) {
        classGrades.put(CourseNodeList.item(k).getNodeName(),
        CourseNodeList.item(k).getNodeValue());
    }
}
classGrades.put(CourseNodeList.item(k).getNodeName(),
        CourseNodeList.item(k).getChildNodes().item(0).getNodeValue());
public static void saveStudentsXML(FileOutputStream file) throws Exception {
    if (xstream == null)
        initXstream();

    xstream.toXML(proctorDAO.studentList, file);
    file.close(); 
 }

 public static void initXstream() {
    xstream = new XStream();
    xstream.alias("student", Student.class);

    xstream.useAttributeFor(Student.class, "lastName");
    xstream.useAttributeFor(Student.class, "firstName");
    xstream.useAttributeFor(Student.class, "id");
    xstream.useAttributeFor(Student.class, "gradYear");
    xstream.aliasAttribute(Student.class, "lastName", "last");
    xstream.aliasAttribute(Student.class, "gradYear", "gc");
    xstream.aliasAttribute(Student.class, "firstName", "first");
}
<list>
  <student first="Ralf" last="Adams" gc="2014" id="100">
     <testingMods value="1" boolMod="2"/>
  </student>
  <student first="Mick" last="Agosti" gc="2014" id="102">
     <testingMods value="1" boolMod="2"/>
  </student>
  <student first="Edmund" last="Baggio" gc="2013" id="302">
     <testingMods value="1" boolMod="6"/>
  </student> 
</list>