3

最近まで、私のXMLファイルのタグ構造はかなり単純でした。しかし、今ではタグ付きのタグのレベルが増え、XMLの解析がより複雑になっています。

新しいXMLファイルの例を次に示します(わかりやすくするためにタグ名を変更しました)。

<SchoolRoster>
   <Student>
      <name>John</name>
      <age>14</age>
      <course>
         <math>A</math>
         <english>B</english>
      </course>
      <course>
         <government>A+</government>
      </course>
   </Student>
   <Student>
      <name>Tom</name>
      <age>13</age>
      <course>
         <gym>A</gym>
         <geography>incomplete</geography>
      </course>
   </Student>
</SchoolRoster>

上記のXMLの重要な機能は、複数の「コース」属性を持つことができ、その中に任意の名前のタグを子として持つことができることです。そして、これらの子はいくつでも存在する可能性があり、「name」、「value」のHashMapに読み込みたいと思います。

public static TreeMap getAllSchoolRosterInformation(String fileName) {
    TreeMap SchoolRoster = new TreeMap();

    try {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        File file = new File(fileName);
        if (file.exists()) {
            Document doc = db.parse(file);
            Element docEle = doc.getDocumentElement();
            NodeList studentList = docEle.getElementsByTagName("Student");

            if (studentList != null && studentList.getLength() > 0) {
                for (int i = 0; i < studentList.getLength(); i++) {

                    Student aStudent = new Student();
                    Node node = studentList.item(i);

                    if (node.getNodeType() == Node.ELEMENT_NODE) {
                        Element e = (Element) node;
                        NodeList nodeList = e.getElementsByTagName("name");
                        aStudent.setName(nodeList.item(0).getChildNodes().item(0).getNodeValue());

                        nodeList = e.getElementsByTagName("age");
                        aStudent.setAge(Integer.parseInt(nodeList.item(0).getChildNodes().item(0).getNodeValue()));

                        nodeList = e.getElementsByTagName("course");
                        if (nodeList != null && nodeList.getLength() > 0) {
                            Course[] courses = new Course[nodeList.getLength()];
                            for (int j = 0; j < nodeList.getLength(); j++) {

                                Course singleCourse = new Course();
                                HashMap classGrades = new HashMap();
                                NodeList CourseNodeList = nodeList.item(j).getChildNodes();

                                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());
                                    }
                                }
                                singleCourse.setRewards(classGrades);
                                Courses[j] = singleCourse;
                            }
                            aStudent.setCourses(Courses);
                        }
                    }
                    SchoolRoster.put(aStudent.getName(), aStudent);
                }
            }
        } else {
            System.exit(1);
        }
    } catch (Exception e) {
        System.out.println(e);
    }
    return SchoolRoster;
}

私が直面している問題は、生徒が「数学」で「A」を取得する代わりに、「数学」でnullを取得することです。(この投稿が長すぎる場合は、短縮する方法を見つけることができます。)

4

3 に答える 3

5

これが私のプロジェクトである場合、HTMLのデータを手動で分析することを避け、代わりにJAXBを使用してJavaにそれを実行させます。このツールを使えば使うほど、大好きになります。これを試すことを検討することをお勧めします。そうする場合、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
}

これにより、次のXMLが生成されました。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<schoolRoster>
    <student>
        <name>Tom</name>
        <age>13</age>
        <courses>
            <course>
                <name>gym</name>
                <grade>A</grade>
            </course>
            <course>
                <name>geography</name>
                <grade>incomplete</grade>
            </course>
        </courses>
    </student>
    <student>
        <name>John</name>
        <age>14</age>
        <courses>
            <course>
                <name>math</name>
                <grade>A</grade>
            </course>
            <course>
                <name>english</name>
                <grade>B</grade>
            </course>
        </courses>
    </student>
</schoolRoster>

これをデータで満たされたSchoolRosterクラスにアンマーシャリングするには、数行のコードしか必要ありません。

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();
  }
}

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]]]]]
于 2012-06-29T20:58:09.220 に答える
4
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());
    }
}

あなたはを呼んgetNodeValue()でいElementます。JDK APIのドキュメントによると、nullを返します。

http://docs.oracle.com/javase/6/docs/api/org/w3c/dom/Node.html

子テキストノードを取得して呼び出す必要がありますgetNodeValue()。これを行うための本当に迅速で汚い方法は次のとおりです。

classGrades.put(CourseNodeList.item(k).getNodeName(),
        CourseNodeList.item(k).getChildNodes().item(0).getNodeValue());

これを本番コードで使用しないでください。それは醜いです。しかし、それはあなたを正しい方向に向けます。

于 2012-06-29T21:26:35.653 に答える
1

@Hovercraftのように、xmlへのシリアル化を処理するためにライブラリを使用することをお勧めします。Xstreamは優れたパフォーマンスを発揮し、使いやすいことがわかりました。 http://x-stream.github.io/

例えば:

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>
于 2012-06-29T21:40:18.457 に答える