เทคนิคการแยกวิเคราะห์ XML


11

ฉันพบว่า XML ค่อนข้างยุ่งยากในการประมวลผลเสมอ ฉันไม่ได้พูดเกี่ยวกับการใช้งานตัวแยกวิเคราะห์ XML: ฉันกำลังพูดถึงการใช้ตัวแยกวิเคราะห์ที่ใช้กระแสอยู่เช่น SAX parser ซึ่งประมวลผลโหนด XML โดยโหนด

ใช่มันง่ายมากที่จะเรียนรู้ API ต่างๆสำหรับ parsers เหล่านี้ แต่เมื่อใดก็ตามที่ฉันดูโค้ดที่ประมวลผล XML ฉันมักจะพบว่ามันค่อนข้างซับซ้อน ปัญหาที่สำคัญดูเหมือนว่าเอกสาร XML จะถูกแยกออกเป็นส่วน ๆ อย่างมีเหตุผลและแต่ละประเภทข้อมูลและคุณลักษณะมักจะแยกออกจากข้อมูลจริงบางครั้งโดยการซ้อนหลายระดับ ดังนั้นเมื่อประมวลผลโหนดเฉพาะใด ๆ เป็นรายบุคคลจำเป็นต้องมีสถานะพิเศษจำนวนมากเพื่อกำหนดว่าเราอยู่ที่ไหนและต้องทำอะไรต่อไป

ตัวอย่างเช่นให้ข้อมูลโค้ดจากเอกสาร XML ทั่วไป:

<book>
  <title>Blah blah</title>
  <author>Blah blah</author>
  <price>15 USD</price>
</book>

... ฉันจะทราบได้อย่างไรเมื่อพบโหนดข้อความที่มีชื่อหนังสือ สมมติว่าเรามีตัวแยกวิเคราะห์ XML ง่ายซึ่งทำหน้าที่เหมือน iterator ให้เราโหนดถัดไปในเอกสาร XML XMLParser.getNextNode()โทรทุกครั้งที่เรา ฉันพบว่าตัวเองเขียนโค้ดอย่างหลีกเลี่ยงไม่ได้:

boolean insideBookNode = false;
boolean insideTitleNode = false;

while (!XMLParser.finished())
{
    ....
    XMLNode n = XMLParser.getNextNode();

    if (n.type() == XMLTextNode)
    {
        if (insideBookNode && insideTitleNode)
        {
            // We have a book title, so do something with it
        }
    }
    else
    {
        if (n.type() == XMLStartTag)
        {
            if (n.name().equals("book")) insideBookNode = true
            else if (n.name().equals("title")) insideTitleNode = true;
        }
        else if (n.type() == XMLEndTag)
        {
            if (n.name().equals("book")) insideBookNode = false;
            else if (n.name().equals("title")) insideTitleNode = false;
        }
    }
}

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

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

<book title="Blah blah" author="blah blah" price="15 USD" />

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

ดังนั้น ... ฉันกำลังทำอะไรผิดหรือเปล่า? มีวิธีที่ดีกว่า? ตัวแยกวิเคราะห์ XML ที่ใช้ในจุดใดที่ยุ่งยากเกินไปดังนั้นตัวแยกวิเคราะห์ DOM ที่มีการแปลงเต็มจึงจำเป็น? ฉันต้องการได้ยินจากโปรแกรมเมอร์คนอื่น ๆ ว่าพวกเขาใช้สำนวนแบบไหนเมื่อประมวลผล XML ด้วยตัวแยกวิเคราะห์ที่ใช้สตรีม ต้องมีการแยกวิเคราะห์ XML ตามกระแสกลายเป็นเครื่องรัฐขนาดใหญ่หรือไม่


2
หากคุณใช้ภาษา. net คุณควรดู linq to xml aka XLinq
Muad'Dib

ขอบคุณฉันคิดว่าฉันเป็นคนเดียวที่มีปัญหานี้ ตรงไปตรงมาฉันมักจะพบว่ารูปแบบ XML ทั้งหมดเป็นอุปสรรคมากกว่าความช่วยเหลือ ใช่มันช่วยให้คนเก็บข้อมูลที่มีโครงสร้างจำนวนมากในไฟล์ข้อความขนาดเล็ก แต่ถ้าคุณต้องการ 20+ ชั้นเรียนในการแกะและทำความเข้าใจกับสิ่งนั้น - โดยไม่มีการรับประกันว่าคุณจะไม่ได้มองสิ่งที่สำคัญมากไปกว่านั้น มันเหมือนกับกระต่ายในจอกศักดิ์สิทธิ์ของ Monty Python
Elise van Looij

คำตอบ:


9

สำหรับฉันแล้วคำถามคืออีกทางหนึ่ง เอกสาร XML กลายเป็นเรื่องยุ่งยากขนาดไหนที่คุณต้องเริ่มใช้ SAX แทนที่จะเป็น DOM

ฉันจะใช้ SAX สำหรับสตรีมข้อมูลขนาดใหญ่มากโดยไม่กำหนด หรือถ้าพฤติกรรมที่ XML ตั้งใจจะเรียกใช้นั้นเป็นตัวขับเคลื่อนเหตุการณ์จริง ๆ ดังนั้นจึงเป็นเช่น SAX

ตัวอย่างที่คุณให้ดูเหมือนกับ DOM กับฉันมาก

  1. โหลด XML
  2. แตกโหนดหัวเรื่องและ "ทำอะไรกับมัน"

แก้ไข: ฉันยังใช้ SAX สำหรับสตรีมที่อาจมีรูปแบบไม่ถูกต้อง แต่ที่ฉันต้องการให้เดาได้ดีที่สุดในการนำข้อมูลออกมา


2
ฉันคิดว่านี่เป็นจุดที่ดี หากคุณแยกวิเคราะห์เอกสารที่มีขนาดใหญ่เกินไปสำหรับ DOM คุณต้องพิจารณาว่าคุณกำลังวิเคราะห์เอกสารที่ใหญ่เกินไปสำหรับXML หรือไม่
Dean Harding

1
+1: ด้วยตัวเลือกฉันจะไปกับ DOM เสมอ น่าเสียดายที่ดูเหมือนว่าข้อกำหนดการออกแบบของเรามักจะรวมถึง "ความสามารถในการจัดการเอกสารขนาดใดก็ได้" และ "ต้องเป็นนักแสดง" ซึ่งค่อนข้างออกกฎโซลูชันที่ใช้ DOM
TMN

3
@TMN ในโลกอุดมคติที่ความต้องการจะตัดออก XML ในตอนแรก
SK-logic

1
@TMN ดูเหมือนว่าหนึ่งในข้อกำหนดของแฟนทอม: "แน่นอนว่าเอกสารทั้งหมดของเรามีเพียงประมาณ 100KB และยิ่งใหญ่ที่สุดที่เราเห็นคือ 1MB แต่คุณไม่เคยรู้ว่าอนาคตจะเป็นอย่างไรดังนั้นเราควรเปิดตัวเลือกของเราไว้ และสร้างเอกสารขนาดใหญ่ที่ไม่มีขีด จำกัด "
Paul Butcher

@ พอลเขียงคุณไม่เคยรู้ ฉันหมายความว่าการถ่ายโอนข้อมูลของ Wikipedia เหมือนกับ XML 30GB
Channel72

7

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

แทนที่จะสำรวจต้นไม้เพื่อค้นหาโหนดที่เฉพาะเจาะจงคุณต้องกำหนดเส้นทางให้กับโหนดนั้น ในกรณีของตัวอย่างของคุณ (ใน pseudocode) มันจะเป็นสิ่งที่ชอบ:

books = parent.xpath ("/ book") // นี่จะให้โหนดหนังสือทั้งหมดแก่คุณ
สำหรับหนังสือแต่ละเล่มในหนังสือ
    title = book.xpath ("/ title / text ()")
    author = book.xpath ("/ author / text ()")
    price = book.xpath ("/ price / text ()")

    // ทำสิ่งต่าง ๆ ด้วยข้อมูล

XPath มีประสิทธิภาพมากกว่านั้นมากคุณสามารถค้นหาโดยใช้เงื่อนไข (ทั้งค่าและคุณสมบัติ) เลือกโหนดเฉพาะในรายการเลื่อนระดับผ่านต้นไม้ ฉันขอแนะนำให้คุณค้นหาข้อมูลเกี่ยวกับวิธีการใช้งานมันถูกนำไปใช้ในไลบรารีการแยกวิเคราะห์จำนวนมาก (ฉันใช้รุ่น. Net Framework และ lxml สำหรับ Python)


ไม่เป็นไรถ้าคุณสามารถรู้และไว้วางใจล่วงหน้าในแบบที่ xml มีโครงสร้าง หากคุณไม่ทราบว่าพูดความกว้างขององค์ประกอบจะถูกระบุเป็นคุณลักษณะของโหนดหรือเป็นแอตทริบิวต์โหนดภายในขนาดโหนดขององค์ประกอบแล้ว XPath จะไม่ช่วยมาก
Elise van Looij

5

ต้องมีการแยกวิเคราะห์ XML ตามกระแสกลายเป็นเครื่องรัฐขนาดใหญ่หรือไม่

โดยปกติแล้วใช่

สำหรับฉันที่จะใช้ parser DOM แบบเต็มเปี่ยมคือเมื่อฉันต้องเลียนแบบส่วนต่างๆของลำดับชั้นของไฟล์ในหน่วยความจำตัวอย่างเช่นเพื่อให้สามารถแก้ไขการอ้างอิงโยงภายในเอกสาร


+1: เริ่มต้นด้วย DOM หลีกเลี่ยง SAX
S.Lott

หรือกับ vtd-xml
vtd-xml-author

4

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

ฉันมักจะใช้ DOM เว้นแต่ว่าขนาดหรือปัญหาเรื่องประสิทธิภาพเป็นอย่างอื่น


1

ไม่เชื่อเรื่องภาษาอย่างสมบูรณ์ แต่โดยทั่วไปฉันมักจะแยกแยะ XML ให้เป็นวัตถุแทนที่จะคิดแยกวิเคราะห์ เวลาเท่านั้นที่ต้องกังวลเกี่ยวกับกลยุทธ์การแยกวิเคราะห์ต่อ se คือถ้าคุณมีปัญหาความเร็ว


ที่ตกอยู่ภายใต้การแยกวิเคราะห์ เว้นแต่ว่า XML ที่เป็นปัญหาจะเป็นผลลัพธ์ของการทำให้เป็นอันดับวัตถุและคุณมีไลบรารี แต่คำถามนี้ไม่ปรากฏ

หลายภาษา / สแต็กมีไลบรารี deserialization
ไวแอตต์บาร์เน็ตต์

ใช่แล้วอะไรนะ? จุดของฉันยังคงถือ - ไม่ทั้งหมดไฟล์ XML ในป่ามาในรูปแบบดังกล่าวและถ้าคุณมีหนึ่งที่ไม่คุณไม่ถามคำถามนี้เช่นเดียวกับคุณใช้ห้องสมุด deserialization ที่และไม่แยกอะไรด้วยตัวคุณเอง จากสตรีมหรืออย่างอื่น

0

มันจะยุ่งยากน้อยกว่าถ้าคุณสามารถใช้ XPath และใน. net ที่ดิน LINQ to XML เป็นนามธรรมสิ่งที่มีเสน่ห์น้อยลงเช่นกัน (แก้ไข - ต้องใช้วิธี DOM แน่นอน)

โดยพื้นฐานแล้วถ้าคุณใช้วิธีการสตรีม (ดังนั้นคุณไม่สามารถใช้ abstractions ที่ดีกว่าที่ต้องใช้ DOM) ฉันคิดว่ามันจะค่อนข้างยุ่งยากและฉันไม่แน่ใจว่าจะมีวิธีแก้ปัญหานี้


หากคุณใช้ XPath คุณกำลังใช้ DOM (ยกเว้นว่าคุณกำลังใช้กับ XPath ผู้ประเมิน XPath เอง)
TMN

ใช่ดังนั้นความคิดเห็นของฉันเกี่ยวกับ abstractions ต้องการ DOM ... แต่ฉันจะอธิบายขอบคุณ!
Steve

0

หากคุณสามารถหา parser ที่ให้ตัววนซ้ำคุณเคยคิดที่จะรักษามันเป็น lexer และใช้เครื่องกำเนิดไฟฟ้าสถานะหรือไม่?

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.