การแยกวิเคราะห์ไฟล์ XML โดยใช้ SAX Parser

1. ภาพรวม

SAX หรือที่เรียกว่าSimple API for XMLใช้สำหรับการแยกวิเคราะห์เอกสาร XML

ในบทช่วยสอนนี้เราจะได้เรียนรู้ว่า SAX คืออะไรและทำไมควรใช้เมื่อใดและอย่างไร

2. SAX : Simple API สำหรับ XML

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

API มีประสิทธิภาพเนื่องจากจะทิ้งเหตุการณ์ทันทีหลังจากที่ได้รับการติดต่อกลับ ดังนั้นSAX จึงมีการจัดการหน่วยความจำที่มีประสิทธิภาพซึ่งแตกต่างจาก DOM เช่น

3. SAX กับ DOM

DOM ย่อมาจาก Document Object Model parser DOM ไม่พึ่งพาเหตุการณ์ นอกจากนี้ยังโหลดเอกสาร XML ทั้งหมดลงในหน่วยความจำเพื่อแยกวิเคราะห์ SAX ประหยัดหน่วยความจำมากกว่า DOM

DOM มีประโยชน์เช่นกัน ตัวอย่างเช่น DOM รองรับ XPath มันทำให้ยังง่ายต่อการใช้งานบนต้นไม้เอกสารทั้งหมดในครั้งเดียวตั้งแต่เอกสารถูกโหลดลงในหน่วยความจำ

4. SAX เทียบกับ StAX

StAX ใหม่กว่า SAX และ DOM มันยืนสำหรับStreaming API สำหรับ XML

ข้อแตกต่างที่สำคัญกับ SAX คือStAX ใช้กลไกการดึงแทนกลไกการผลักของ SAX (โดยใช้การเรียกกลับ)

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

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

ซึ่งแตกต่างจาก SAX ตรงที่ไม่มีการตรวจสอบความถูกต้องของสคีมาเป็นหนึ่งในคุณสมบัติของมัน

5. การแยกวิเคราะห์ไฟล์ XML โดยใช้ Custom Handler

ตอนนี้เรามาใช้ XML ต่อไปนี้ที่แสดงถึงเว็บไซต์ Baeldung และบทความของมัน:

   Parsing an XML File Using SAX Parser SAX Parser's Lorem ipsum...   Parsing an XML File Using DOM Parser DOM Parser's Lorem ipsum...   Parsing an XML File Using StAX Parser StAX's Lorem ipsum...   

เราจะเริ่มต้นด้วยการสร้าง POJO สำหรับองค์ประกอบรูทBaeldungและลูก ๆ ของเรา:

public class Baeldung { private List articleList; // usual getters and setters } 
public class BaeldungArticle { private String title; private String content; // usual getters and setters } 

เราจะยังคงโดยการสร้างBaeldungHandler คลาสนี้จะใช้วิธีการโทรกลับที่จำเป็นในการจับภาพเหตุการณ์

เราจะลบล้างวิธีการสี่วิธีจาก Superclass DefaultHandler โดยแต่ละตัวจะระบุลักษณะของเหตุการณ์:

    • อักขระ (ถ่าน [], int, int)รับอักขระที่มีขอบเขต เราจะแปลงเป็นStringและเก็บไว้ในตัวแปรของBaeldungHandler
    • startDocument ()ถูกเรียกใช้เมื่อการแยกวิเคราะห์เริ่มต้นขึ้น - เราจะใช้มันเพื่อสร้างอินสแตนซ์Baeldungของเรา
    • startElement ()ถูกเรียกใช้เมื่อการแยกวิเคราะห์เริ่มต้นสำหรับองค์ประกอบ - เราจะใช้เพื่อสร้างอินสแตนซ์ListหรือBaeldungArticle - qNameช่วยให้เราสร้างความแตกต่างระหว่างทั้งสองประเภท
    • endElement ()ถูกเรียกใช้เมื่อการแยกวิเคราะห์สิ้นสุดลงสำหรับองค์ประกอบ - นี่คือเวลาที่เรากำหนดเนื้อหาของแท็กให้กับตัวแปรตามลำดับ

ด้วยการเรียกกลับทั้งหมดที่กำหนดตอนนี้เราสามารถเขียนคลาสBaeldungHandler :

public class BaeldungHandler extends DefaultHandler { private static final String ARTICLES = "articles"; private static final String ARTICLE = "article"; private static final String TITLE = "title"; private static final String CONTENT = "content"; private Baeldung website; private String elementValue; @Override public void characters(char[] ch, int start, int length) throws SAXException { elementValue = new String(ch, start, length); } @Override public void startDocument() throws SAXException { website = new Baeldung(); } @Override public void startElement(String uri, String lName, String qName, Attributes attr) throws SAXException { switch (qName) { case ARTICLES: website.articleList = new ArrayList(); break; case ARTICLE: website.articleList.add(new BaeldungArticle()); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { switch (qName) { case TITLE: latestArticle().title = elementValue; break; case CONTENT: latestArticle().content = elementValue; break; } } private BaeldungArticle latestArticle() { List articleList = website.articleList; int latestArticleIndex = articleList.size() - 1; return articleList.get(latestArticleIndex); } public Baeldung getWebsite() { return website; } } 

นอกจากนี้ยังเพิ่มค่าคงที่สตริงเพื่อเพิ่มความสามารถในการอ่าน วิธีการดึงบทความที่พบล่าสุดก็สะดวกเช่นกัน ในที่สุดเราต้องการผู้เริ่มต้นสำหรับวัตถุBaeldung

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

6. การทดสอบโปรแกรมแยกวิเคราะห์

ในการทดสอบตัวแยกวิเคราะห์เราจะสร้างอินสแตนซ์SaxFactory , SaxParserและBaeldungHandler :

SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser saxParser = factory.newSAXParser(); SaxParserMain.BaeldungHandler baeldungHandler = new SaxParserMain.BaeldungHandler(); 

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

saxParser.parse("src/test/resources/sax/baeldung.xml", baeldungHandler); SaxParserMain.Baeldung result = baeldungHandler.getWebsite(); assertNotNull(result); List articles = result.getArticleList(); assertNotNull(articles); assertEquals(3, articles.size()); SaxParserMain.BaeldungArticle articleOne = articles.get(0); assertEquals("Parsing an XML File Using SAX Parser", articleOne.getTitle()); assertEquals("SAX Parser's Lorem ipsum...", articleOne.getContent()); SaxParserMain.BaeldungArticle articleTwo = articles.get(1); assertEquals("Parsing an XML File Using DOM Parser", articleTwo.getTitle()); assertEquals("DOM Parser's Lorem ipsum...", articleTwo.getContent()); SaxParserMain.BaeldungArticle articleThree = articles.get(2); assertEquals("Parsing an XML File Using StAX Parser", articleThree.getTitle()); assertEquals("StAX Parser's Lorem ipsum...", articleThree.getContent()); 

ตามที่คาดไว้baeldungได้รับการแยกวิเคราะห์อย่างถูกต้องและมีวัตถุย่อยที่รอคอย

7. สรุป

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

ตามปกติรหัสสำหรับบทความนี้มีอยู่บน GitHub