Contents

วิธีอ่านและเขียนไฟล์ XML ด้วย Java

ไฟล์ XML สามารถตอบสนองวัตถุประสงค์ที่หลากหลาย รวมถึงการจัดเก็บข้อมูล ก่อนที่ JSON จะได้รับความนิยม XML เป็นรูปแบบที่ต้องการสำหรับการนำเสนอ จัดเก็บ และขนส่งข้อมูลที่มีโครงสร้าง

แม้ว่าความแพร่หลายจะลดลงในยุคปัจจุบัน แต่ก็ยังอาจพบเห็น XML เป็นครั้งคราว ดังนั้นจึงจำเป็นอย่างยิ่งที่จะต้องได้รับความเชี่ยวชาญในการทำงานกับรูปแบบนี้ สำรวจความซับซ้อนของการใช้ Document Object Model (DOM) Application Programming Interface (API) สำหรับการอ่านและเขียนเอกสาร XML โดยใช้ Java เป็นเครื่องมือหลักของคุณ

ข้อกำหนดสำหรับการประมวลผล XML ใน Java

Java Standard Edition หรือ SE ประกอบด้วย Java API สำหรับการประมวลผล XML หรือที่เรียกกันทั่วไปว่า JAXP ซึ่งเป็นเฟรมเวิร์กที่ครอบคลุมซึ่งครอบคลุมแง่มุมต่างๆ ของการจัดการ XML ละครที่กว้างขวางนี้ประกอบด้วยองค์ประกอบสำคัญหลายประการ ได้แก่:

Document Object Model (DOM) ครอบคลุมชุดของคลาสที่อำนวยความสะดวกในการจัดการส่วนประกอบ XML รวมถึงองค์ประกอบ โหนด และคุณลักษณะ อย่างไรก็ตาม เนื่องจากการออกแบบให้โหลดไฟล์ XML ทั้งหมดลงในหน่วยความจำเพื่อการประมวลผล จึงไม่มีความพร้อมในการจัดการเอกสารขนาดใหญ่ได้อย่างมีประสิทธิภาพ

Simple API สำหรับ XML (SAX) เป็นกลไกการแยกวิเคราะห์แบบน้ำหนักเบาที่ออกแบบมาโดยเฉพาะสำหรับการจัดการเอกสาร XML ต่างจาก Document Object Model (DOM) ซึ่งสร้างโครงสร้างต้นไม้ทั้งหมดในระหว่างการประมวลผล SAX ดำเนินการโดยการยิงเหตุการณ์ตามเนื้อหา XML ที่พบขณะแยกวิเคราะห์ไฟล์ วิธีการนี้ช่วยลดการใช้หน่วยความจำและช่วยให้มีความยืดหยุ่นมากขึ้นในแง่ของการจัดการข้อมูลจำนวนมาก อย่างไรก็ตาม การใช้ SAX อาจค่อนข้างท้าทายเมื่อเทียบกับการใช้ DOM เนื่องจากการพึ่งพากระบวนทัศน์การเขียนโปรแกรมตามเหตุการณ์

StAX หรือ Streaming API สำหรับ XML แสดงถึงส่วนเพิ่มเติมล่าสุดในขอบเขตของการประมวลผล XML ด้วยความสามารถด้านประสิทธิภาพที่น่าประทับใจในแง่ของการกรอง การประมวลผล และการแก้ไขสตรีม เครื่องมืออันทรงพลังนี้จัดการเพื่อให้บรรลุวัตถุประสงค์โดยไม่จำเป็นต้องโหลดเอกสาร XML ขายส่งลงในหน่วยความจำ ตรงกันข้ามกับสถาปัตยกรรมที่ขับเคลื่อนด้วยเหตุการณ์ซึ่ง SAX API ชื่นชอบนั้น StAX ใช้วิธีการดึงข้อมูลที่ทำให้ง่ายขึ้นและเป็นมิตรกับผู้ใช้มากขึ้นเมื่อพูดถึงการเขียนโค้ด

ในการจัดการข้อมูล XML ภายในแอปพลิเคชัน Java จำเป็นต้องรวมแพ็คเกจบางอย่างที่อำนวยความสะดวกในการใช้งานนี้ แพ็คเกจเหล่านี้มีวิธีการและคลาสที่หลากหลายสำหรับการแยกวิเคราะห์ จัดการ และสร้างเอกสาร XML

 import javax.xml.parsers.*;
import javax.xml.transform.*;
import org.w3c.dom.*;

กำลังเตรียมไฟล์ XML ตัวอย่าง

/th/images/sample-xml-file-from-microsoft.jpeg

หากต้องการทำความเข้าใจโค้ดตัวอย่างและแนวคิดเบื้องหลัง ให้ใช้ตัวอย่าง ไฟล์ XML จาก Microsoft นี่เป็นข้อความที่ตัดตอนมา:

 <?xml version="1.0"?>
<catalog>
  <book id="bk101">
    <author>Gambardella, Matthew</author>
    <title>XML Developer's Guide</title>
    <genre>Computer</genre>
    <price>44.95</price>
    <publish_date>2000-10-01</publish_date>
    <description>An in-depth look at creating applications
      with XML.</description>
  </book>
  <book id="bk102">
    <author>Ralls, Kim</author>
...snipped... 

อ่านไฟล์ XML ด้วย DOM API

เพื่อประมวลผลไฟล์ XML อย่างมีประสิทธิภาพโดยใช้ Document Object Model (DOM) Application Programming Interface เราต้องสร้างอินสแตนซ์ของคลาส DocumentBuilder ก่อน ซึ่งจะอำนวยความสะดวกในการแยกวิเคราะห์เอกสาร XML

 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder(); 

ตอนนี้เราสามารถเลือกจัดเก็บเอกสารทั้งหมดไว้ในหน่วยความจำได้ โดยเริ่มจากองค์ประกอบรูท XML ซึ่งในกรณีนี้จะสอดคล้องกับองค์ประกอบ “แค็ตตาล็อก”

 // XML file to read
File file = "<path_to_file>";
Document document = builder.parse(file);
Element catalog = document.getDocumentElement();

แท้จริงแล้ว ด้วยการใช้วิธีการนี้ เราจึงสามารถเข้าถึงเอกสาร XML ทั้งหมดได้อย่างสมบูรณ์ โดยเริ่มจากโหนดหลัก ซึ่งก็คือองค์ประกอบ"แค็ตตาล็อก"

การแยกข้อมูลโดยใช้ DOM API

เมื่อคุณได้รับองค์ประกอบรูทโดยใช้ตัวแยกวิเคราะห์ XML แล้ว คุณสามารถใช้ Document Object Model (DOM) API เพื่อเข้าถึงข้อมูลอันมีค่าภายในองค์ประกอบนั้นได้ ตามตัวอย่าง การดึงข้อมูลทายาทลำดับต้นของอิลิเมนต์รากทั้งหมดแล้ววนซ้ำองค์ประกอบเหล่านั้นเป็นแนวทางที่ใช้งานได้จริง อย่างไรก็ตาม โปรดทราบว่าเมธอด getChildNodes() จะส่งคืนรายการย่อยทุกประเภท รวมถึงโหนดข้อความและโหนดความคิดเห็น ซึ่งไม่เกี่ยวข้องกับงานปัจจุบันของเรา ดังนั้นเราจึงควรกำหนดเป้าหมายเฉพาะองค์ประกอบลูกโดยเฉพาะเมื่อประมวลผลผลลัพธ์เหล่านี้

 NodeList books = catalog.getChildNodes();

for (int i = 0, ii = 0, n = books.getLength() ; i < n ; i\+\+) {
  Node child = books.item(i);

  if ( child.getNodeType() != Node.ELEMENT_NODE )
    continue;

  Element book = (Element)child;
  // work with the book Element here
}

หากต้องการค้นหาองค์ประกอบย่อยภายใต้พาเรนต์ในเอกสาร XML โดยใช้ C# เราสามารถสร้างวิธีการคงที่ที่วนซ้ำการรวบรวมโหนดย่อยเพื่อระบุองค์ประกอบที่ต้องการตามชื่อของมัน หากค้นพบองค์ประกอบในระหว่างกระบวนการนี้ องค์ประกอบนั้นจะถูกส่งคืน มิฉะนั้น null แสดงถึงผลลัพธ์

 static private Node findFirstNamedElement(Node parent,String tagName)
{
  NodeList children = parent.getChildNodes();

  for (int i = 0, in = children.getLength() ; i < in ; i\+\+) {
    Node child = children.item(i);

    if (child.getNodeType() != Node.ELEMENT_NODE)
      continue;

    if (child.getNodeName().equals(tagName))
      return child;
  }

  return null;
}

โปรดทราบว่า DOM API จะจัดประเภทเนื้อหาข้อความที่อยู่ภายในองค์ประกอบเป็นแต่ละโหนดของหมวดหมู่ TEXT\_NODE เนื้อหาต้นฉบับอาจประกอบด้วยโหนดข้อความหลายโหนดที่ต่อเนื่องกัน ซึ่งจำเป็นต้องมีการจัดการเฉพาะเพื่อดึงข้อความขององค์ประกอบที่กำหนด:

 static private String getCharacterData(Node parent)
{
  StringBuilder text = new StringBuilder();

  if ( parent == null )
    return text.toString();

  NodeList children = parent.getChildNodes();

  for (int k = 0, kn = children.getLength() ; k < kn ; k\+\+) {
    Node child = children.item(k);

    if (child.getNodeType() != Node.TEXT_NODE)
      break;

    text.append(child.getNodeValue());
  }

  return text.toString();
}

การใช้ฟังก์ชันอรรถประโยชน์ที่มีให้ ให้เราตรวจสอบตัวอย่างที่ดึงข้อมูลที่เกี่ยวข้องจากเอกสาร XML ที่แสดงแคตตาล็อกหนังสือ รหัสที่ตามมาจะแสดงรายละเอียดที่ครอบคลุมเกี่ยวกับสิ่งพิมพ์แต่ละรายการที่มีอยู่ในแค็ตตาล็อกดังกล่าว:

 NodeList books = catalog.getChildNodes();

for (int i = 0, ii = 0, n = books.getLength() ; i < n ; i\+\+) {
  Node child = books.item(i);

  if (child.getNodeType() != Node.ELEMENT_NODE)
    continue;

  Element book = (Element)child;
  ii\+\+;

  String id = book.getAttribute("id");
  String author = getCharacterData(findFirstNamedElement(child, "author"));
  String title = getCharacterData(findFirstNamedElement(child, "title"));
  String genre = getCharacterData(findFirstNamedElement(child, "genre"));
  String price = getCharacterData(findFirstNamedElement(child, "price"));
  String pubdate = getCharacterData(findFirstNamedElement(child, "pubdate"));
  String descr = getCharacterData(findFirstNamedElement(child, "description"));

  System.out.printf("%3d. book id = %s\n" \+
    " author: %s\n" \+
    " title: %s\n" \+
    " genre: %s\n" \+
    " price: %s\n" \+
    " pubdate: %s\n" \+
    " descr: %s\n",
    ii, id, author, title, genre, price, pubdate, descr);
}

ต่อไปนี้เป็นคำอธิบายโค้ดทีละขั้นตอน:

รหัสจะอ่านลูกของลูกหลานหรือส่วนประกอบของรากซึ่งทำหน้าที่เป็นรากฐานสำหรับโครงสร้างทั้งหมด

สำหรับโหนดย่อยแต่ละโหนดซึ่งสอดคล้องกับหนังสือเล่มใดเล่มหนึ่ง โปรแกรมจะตรวจสอบว่าโครงสร้างข้อมูลที่ซ่อนอยู่นั้นมีคุณสมบัติของการเป็น ELEMENT\_NODE หรือไม่ ในกรณีที่ไม่เป็นไปตามข้อกำหนดเบื้องต้น กระบวนการจะดำเนินการวนซ้ำครั้งต่อไป

หากพบโหนดลูกประเภท ELEMENT\_NODE ในกระบวนการแวะผ่านแผนผัง DOM คุณสมบัติ ลูก จะถูกบังคับเข้าสู่อินสแตนซ์ของอินเทอร์เฟซ องค์ประกอบ

การดำเนินการโปรแกรมในภายหลังเกี่ยวข้องกับการดึงข้อมูลคุณลักษณะและข้อมูลตัวละครหลายรายการที่เกี่ยวข้องกับองค์ประกอบของหนังสือที่ระบุ เช่น ตัวระบุที่ไม่ซ้ำกัน (“id”) ชื่อผู้แต่ง ชื่อ ประเภท ประเภท ราคา วันที่ตีพิมพ์ และข้อมูลคำอธิบาย ข้อมูลที่แยกออกมานี้จะถูกพิมพ์ไปยังคอนโซลในภายหลังโดยใช้เมธอด System.out.printf() เพื่อวัตถุประสงค์ในการนำเสนอ

นี่คือลักษณะของผลลัพธ์:

/th/images/parsing-xml-in-java-source-code-and-output.jpeg

การเขียนเอาต์พุต XML โดยใช้ Transform API

Java นำเสนอ XML Transformation API เพื่อใช้ในการจัดการข้อมูล XML API นี้ใช้ร่วมกับการเปลี่ยนแปลงข้อมูลประจำตัวเพื่อสร้างเอาต์พุต เพื่อแสดงให้เห็น ให้พิจารณาเพิ่มแค็ตตาล็อกตัวอย่างก่อนหน้านี้โดยการรวมองค์ประกอบหนังสือใหม่เข้าด้วยกัน

ข้อมูลที่เกี่ยวข้องกับงานวรรณกรรม รวมถึงผู้แต่งและชื่อเรื่อง อาจได้รับจากทรัพยากรภายนอก เช่น ฐานข้อมูลหรือไฟล์ทรัพย์สิน ไฟล์คุณสมบัติที่ให้มาทำหน้าที่เป็นแบบจำลองสำหรับจุดประสงค์นี้

 id=bk113
author=Jane Austen
title=Pride and Prejudice
genre=Romance
price=6.99
publish_date=2010-04-01
description="It is a truth universally acknowledged, that a single man in possession of a good fortune must be in want of a wife." So begins Pride and Prejudice, Jane Austen's witty comedy of manners-one of the most popular novels of all time-that features splendidly civilized sparring between the proud Mr. Darcy and the prejudiced Elizabeth Bennet as they play out their spirited courtship in a series of eighteenth-century drawing-room intrigues.

ในการประมวลผลเอกสาร XML จำเป็นต้องใช้เทคนิคการแยกวิเคราะห์ที่อธิบายไว้ก่อนหน้านี้ สิ่งนี้เกี่ยวข้องกับการทำลายโครงสร้างข้อความของไฟล์และแยกข้อมูลที่เกี่ยวข้องเพื่อการวิเคราะห์หรือการจัดการเพิ่มเติม

 File file = ...; // XML file to read
Document document = builder.parse(file);
Element catalog = document.getDocumentElement();

การใช้คลาสคุณสมบัติที่ให้มาภายในภาษาการเขียนโปรแกรม Java ทำให้สามารถดึงและประมวลผลข้อมูลที่จัดเก็บไว้ในไฟล์การกำหนดค่าภายนอกแยกต่างหากที่เรียกว่าไฟล์"คุณสมบัติ"ได้อย่างมีประสิทธิภาพ กระบวนการนี้เกี่ยวข้องกับความซับซ้อนในการเขียนโค้ดขั้นต่ำ ทำให้การรวมการตั้งค่าหรือการตั้งค่าที่ผู้ใช้กำหนดเข้ากับตรรกะของแอปพลิเคชันโดยรวมมีความคล่องตัว

 String propsFile = "<path_to_file>";
Properties props = new Properties();

try (FileReader in = new FileReader(propsFile)) {
  props.load(in);
}

เมื่อโหลดไฟล์คุณสมบัติแล้ว เราอาจแยกค่าที่ต้องการมาเพิ่มเติมจากไฟล์ดังกล่าว

 String id = props.getProperty("id");
String author = props.getProperty("author");
String title = props.getProperty("title");
String genre = props.getProperty("genre");
String price = props.getProperty("price");
String publish_date = props.getProperty("publish_date");
String descr = props.getProperty("description");

ตอนนี้สร้างองค์ประกอบหนังสือที่ว่างเปล่า

 Element book = document.createElement("book");
book.setAttribute("id", id);

การรวมองค์ประกอบแต่ละส่วนของหนังสือไว้ในคลังข้อความถือเป็นความพยายามที่ไม่ซับซ้อน เพื่ออำนวยความสะดวกในกระบวนการนี้ เราอาจรวบรวมแค็ตตาล็อกของการกำหนดที่จำเป็นโดยจัดเป็นคอลเลกชันที่เรียกว่า"รายการ"โดยการดำเนินการที่เกิดซ้ำภายในรายการนี้ รายการที่เกี่ยวข้องอาจผนวกเข้ากับกรอบการเล่าเรื่องที่กว้างขึ้นได้อย่างมีประสิทธิภาพ

 List<String> elnames =Arrays.asList("author", "title", "genre", "price",
  "publish_date", "description");

for (String elname : elnames) {
  Element el = document.createElement(elname);
  Text text = document.createTextNode(props.getProperty(elname));
  el.appendChild(text);
  book.appendChild(el);
}

catalog.appendChild(book);

ปัจจุบันส่วนประกอบแค็ตตาล็อกดังกล่าวมีเอนทิตีหนังสือเพิ่มเติมที่เพิ่งเปิดตัว งานเดียวที่เหลืออยู่คือการกำหนดเอกสาร Extensible Markup Language (XML) ที่ได้รับการแก้ไขซึ่งครอบคลุมการอัปเดตดังกล่าว

ในการสร้างเอกสาร XML โดยใช้หม้อแปลงไฟฟ้า เราต้องได้รับอินสแตนซ์ของหม้อแปลงดังกล่าวก่อน ซึ่งสามารถทำได้โดยการใช้โค้ดที่จำเป็นภายในภาษาโปรแกรมหรือสภาพแวดล้อมการพัฒนา ตัวอย่างเช่น ใน Python เราสามารถใช้ไลบรารี transformers และฟังก์ชันที่เกี่ยวข้องเพื่อสร้างอินสแตนซ์ของหม้อแปลงสำหรับใช้กับงานการประมวลผลภาษาธรรมชาติ

 TransformerFactory tfact = TransformerFactory.newInstance();
Transformer tform = tfact.newTransformer();
tform.setOutputProperty(OutputKeys.INDENT, "yes");
tform.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "3"); 

คุณสามารถใช้เมธอด setOutputProperty() เพื่อระบุระดับการเยื้องที่ต้องการในเอาต์พุตที่สร้างขึ้น

ขั้นตอนสุดท้ายเกี่ยวข้องกับการดำเนินกระบวนการแปลง ผลลัพธ์จะแสดงผ่านเอาท์พุตสตรีม ซึ่งสามารถสังเกตได้โดยการตรวจสอบคอนโซลหรือเทอร์มินัลที่โปรแกรมกำลังทำงานอยู่

 tform.transform(new DOMSource(document), new StreamResult(System.out));

หากต้องการบันทึกเอาต์พุตของโปรแกรมลงในไฟล์แทนการพิมพ์ลงในคอนโซล เราสามารถใช้วิธีการต่อไปนี้:

 tform.transform(new DOMSource(document), new StreamResult(new File("output.xml")));

เพื่อที่จะดำเนินการทั้งการอ่านและการเขียนไฟล์ Extensible Markup Language (XML) โดยใช้ภาษาโปรแกรม Java จะต้องดำเนินการชุดของการดำเนินการตามขั้นตอนตามลำดับ ซึ่งรวมถึงการกำหนดออบเจ็กต์เอกสาร XML การสร้างโหนดภายในเอกสารนั้น การแนบองค์ประกอบย่อยเข้ากับโหนดหลัก การระบุแอตทริบิวต์ขององค์ประกอบ การต่อท้ายหรือการแทรกโหนดใหม่ที่ตำแหน่งต่างๆ ภายในเอกสาร และสุดท้ายปิดแท็กใดๆ ที่เปิดอยู่ก่อนที่จะยุติกระบวนการ

ตอนนี้คุณรู้วิธีอ่านและเขียนไฟล์ XML ด้วย Java แล้ว

การใช้ Java เพื่อแยกวิเคราะห์และจัดการ Extensible Markup Language (XML) ถือเป็นความสามารถที่ขาดไม่ได้ซึ่งมักพบในแอปพลิเคชันเชิงปฏิบัติ Document Object Model (DOM) และ API การเปลี่ยนแปลงมีประโยชน์อย่างมากสำหรับจุดประสงค์นี้

การทำความเข้าใจ Document Object Model (DOM) อย่างครอบคลุมเป็นสิ่งที่ขาดไม่ได้สำหรับนักพัฒนาที่ต้องการสร้างสคริปต์ฝั่งไคลเอ็นต์สำหรับแอปพลิเคชันบนเว็บหรือเว็บไซต์ โชคดีที่สถาปัตยกรรมของ DOM ได้รับการกำหนดมาตรฐานสำหรับภาษาการเขียนโปรแกรมต่างๆ ทำให้สามารถจัดการได้อย่างสม่ำเสมอผ่านโค้ดที่เขียนในภาษาต่างๆ เช่น Java และ JavaScript