Pertanyaan saya adalah: Bagaimana saya bisa mendapatkan elemen langsung di bawah elemen induk tertentu ketika ada elemen lain dengan nama yang sama dengan "cucu &" dari elemen induk.
Saya menggunakan Java DOM library untuk mengurai XML Elemen dan saya mengalami masalah. Berikut ini beberapa (sebagian kecil) dari xml yang saya gunakan:
<notifications>
<notification>
<groups>
<group name="zip-group.zip" zip="true">
<file location="C:\valid\directory\" />
<file location="C:\another\valid\file.doc" />
<file location="C:\valid\file\here.txt" />
</group>
</groups>
<file location="C:\valid\file.txt" />
<file location="C:\valid\file.xml" />
<file location="C:\valid\file.doc" />
</notification>
</notifications>
Seperti yang bisa Anda lihat, ada dua tempat Anda dapat menempatkan elemen <file>
. Baik di dalam grup atau di luar grup. Saya benar-benar menginginkannya terstruktur dengan cara ini karena lebih ramah pengguna.
Sekarang, setiap kali saya memanggil notificationElement.getElementsByTagName("file");
itu memberi saya semua elemen <file>
, termasuk yang berada di bawah elemen <group>
. Saya menangani setiap jenis file ini secara berbeda, sehingga fungsi ini tidak diinginkan.
Saya telah memikirkan dua solusi:
<notification>
atau <group>
.&<file>
kedua untuk menghindari kebingungan.Kedua solusi tersebut tidak lebih baik daripada membiarkannya seperti apa adanya dan hanya mendapatkan elemen &<file>
yang merupakan anak langsung dari elemen <notification>
.
Saya terbuka untuk komentar dan jawaban IMPO tentang cara terbaik untuk melakukan hal ini, tetapi saya sangat tertarik dengan solusi DOM karena itulah yang digunakan oleh proyek ini. Terima kasih.
Anda bisa menggunakan XPath untuk ini, menggunakan dua jalur untuk mendapatkannya dan memprosesnya secara berbeda.
Untuk mendapatkan node &<File>
anak langsung dari <notifikasi>
gunakan //notifikasi/file
dan untuk yang ada di <grup>
gunakan //groups/group/file
.
Ini adalah contoh sederhana:
public class SO10689900 {
public static void main(String[] args) throws Exception {
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader("<notifications>\n" +
" <notification>\n" +
" <groups>\n" +
" <group name=\"zip-group.zip\" zip=\"true\">\n" +
" <File location=\"C:\\valid\\directory\\\" />\n" +
" <File location=\"C:\\this\\file\\doesn't\\exist.grr\" />\n" +
" <File location=\"C:\\valid\\file\\here.txt\" />\n" +
" </group>\n" +
" </groups>\n" +
" <File location=\"C:\\valid\\file.txt\" />\n" +
" <File location=\"C:\\valid\\file.xml\" />\n" +
" <File location=\"C:\\valid\\file.doc\" />\n" +
" </notification>\n" +
"</notifications>")));
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr1 = xpath.compile("//notification/file");
NodeList nodes = (NodeList)expr1.evaluate(doc, XPathConstants.NODESET);
System.out.println("Files in //notification");
printFiles(nodes);
XPathExpression expr2 = xpath.compile("//groups/group/file");
NodeList nodes2 = (NodeList)expr2.evaluate(doc, XPathConstants.NODESET);
System.out.println("Files in //groups/group");
printFiles(nodes2);
}
public static void printFiles(NodeList nodes) {
for (int i = 0; i < nodes.getLength(); ++i) {
Node file = nodes.item(i);
System.out.println(file.getAttributes().getNamedItem("location"));
}
}
}
Ini harus menghasilkan output:
Files in //notification
location="C:\valid\file.txt"
location="C:\valid\file.xml"
location="C:\valid\file.doc"
Files in //groups/group
location="C:\valid\directory\"
location="C:\this\file\doesn't\exist.grr"
location="C:\valid\file\here.txt"
Nah, solusi DOM untuk pertanyaan ini sebenarnya cukup sederhana, meskipun tidak terlalu elegan Ketika saya mengiterasi filesNodeList
yang dikembalikan ketika saya memanggil notificationElement.getElementsByTagName("file");
Saya hanya memeriksa apakah nama simpul induknya adalah "notifikasi. " Jika tidak, maka saya abaikan karena akan ditangani oleh elemen <group>
. Inilah solusi kode saya:
for (int j = 0; j < filesNodeList.getLength(); j++) {
Element fileElement = (Element) filesNodeList.item(j);
if (!fileElement.getParentNode().getNodeName().equals("notification")) {
continue;
}
...
}
Jika Anda tetap menggunakan API DOM
NodeList nodeList = doc.getElementsByTagName("notification")
.item(0).getChildNodes();
// get the immediate child (1st generation)
for (int i = 0; i < nodeList.getLength(); i++)
switch (nodeList.item(i).getNodeType()) {
case Node.ELEMENT_NODE:
Element element = (Element) nodeList.item(i);
System.out.println("element name: " + element.getNodeName());
// check the element name
if (element.getNodeName().equalsIgnoreCase("file"))
{
// do something with you "file" element (child first generation)
System.out.println("element name: "
+ element.getNodeName() + " attribute: "
+ element.getAttribute("location"));
}
break;
}
Tugas pertama kita adalah mendapatkan elemen "Notification" (dalam hal ini -item pertama (0)-) dan semua anak-anaknya:
NodeList nodeList = doc.getElementsByTagName("notification")
.item(0).getChildNodes();
(nanti Anda dapat bekerja dengan semua elemen menggunakan mendapatkan semua elemen).
Untuk setiap anak dari "Notification":
for (int i = 0; i < nodeList.getLength(); i++)
Anda terlebih dahulu mendapatkan jenisnya untuk melihat apakah itu sebuah elemen:
switch (nodeList.item(i).getNodeType()) {
case Node.ELEMENT_NODE:
//.......
break;
}
Jika demikian, maka Anda mendapatkan anak "file" , yang bukan cucu "Notification"
dan Anda dapat memeriksanya:
if (element.getNodeName().equalsIgnoreCase("file"))
{
// do something with you "file" element (child first generation)
System.out.println("element name:"
+ element.getNodeName() + " attribute: "
+ element.getAttribute("location"));
}
dan ouptutnya adalah:
element name: file
element name:file attribute: C:\valid\file.txt
element name: file
element name:file attribute: C:\valid\file.xml
element name: file
element name:file attribute: C:\valid\file.doc