กำลังแยกวิเคราะห์เอกสาร xml แยกวิเคราะห์ข้อมูล XML การสร้างอินสแตนซ์ตัวแยกวิเคราะห์

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

การใช้ส่วนขยาย SimpleXMLใน PHP ซึ่งเพิ่มกลับมาใน PHP 5.0 การทำงานกับ XML นั้นง่ายและสะดวกมาก ในบทความนี้ ฉันจะแสดงวิธีการทำ

พื้นฐานของการใช้งาน

เริ่มต้นด้วยตัวอย่างต่อไปนี้ languages.xml:


>

> 1972>
> เดนนิส ริตชี่ >
>

> 1995>
> ราสมุส เลอร์ดอร์ฟ >
>

> 1995>
> เจมส์ กอสลิง >
>
>

เอกสาร XML นี้ประกอบด้วยรายการภาษาการเขียนโปรแกรมพร้อมข้อมูลบางอย่างเกี่ยวกับแต่ละภาษา: ปีที่นำไปใช้และชื่อผู้สร้าง

ขั้นตอนแรกคือการโหลด XML โดยใช้ฟังก์ชันต่างๆ simplexml_load_file(), หรือ simplexml_load_string()- ตามที่ชื่อของฟังก์ชันแนะนำ อันแรกจะโหลด XML จากไฟล์ และอันที่สองจะโหลด XML จากสตริง

ฟังก์ชันทั้งสองอ่านแผนผัง DOM ทั้งหมดลงในหน่วยความจำและส่งกลับวัตถุ SimpleXMLElement- ในตัวอย่างข้างต้น ออบเจ็กต์จะถูกจัดเก็บไว้ในตัวแปร $ languages ​​​​ คุณสามารถใช้ฟังก์ชั่นต่างๆ var_dump()หรือ พิมพ์_r()เพื่อรับรายละเอียดเกี่ยวกับวัตถุที่ส่งคืนหากคุณต้องการ

วัตถุ SimpleXMLElement
[lang] => อาร์เรย์
[ 0 ] => วัตถุ SimpleXMLElement
[@attributes] => อาร์เรย์
[ชื่อ] => ซี
[ปรากฏ] => 1972
[ผู้สร้าง] => เดนนิส ริตชี่
[ 1 ] => วัตถุ SimpleXMLElement
[@attributes] => อาร์เรย์
[ชื่อ] => PHP
[ปรากฏ] => 1995
[ผู้สร้าง] => ราสมุส เลอร์ดอร์ฟ
[ 2 ] => วัตถุ SimpleXMLElement
[@attributes] => อาร์เรย์
[ชื่อ] => ชวา
[ปรากฏ] => 1995
[ผู้สร้าง] => เจมส์ กอสลิง
)
)

XML นี้มีองค์ประกอบราก ภาษาซึ่งภายในมีองค์ประกอบอยู่ 3 ประการ หลางแต่ละองค์ประกอบอาร์เรย์สอดคล้องกับองค์ประกอบ หลางในเอกสาร XML

คุณสามารถเข้าถึงคุณสมบัติของวัตถุโดยใช้ตัวดำเนินการ -> - ตัวอย่างเช่น $ languages->lang จะส่งคืนออบเจ็กต์ SimpleXMLElement ที่ตรงกับองค์ประกอบแรกให้กับคุณ หลาง- วัตถุนี้มีคุณสมบัติสองประการ: ปรากฏ และ ผู้สร้าง

$ ภาษา -> lang [ 0 ] -> ปรากฏ ;
$ภาษา -> lang [ 0 ] -> ผู้สร้าง ;

การแสดงรายการภาษาและการแสดงคุณสมบัติสามารถทำได้ง่ายมากโดยใช้ลูปมาตรฐานเช่น foreach.

foreach ($ภาษา -> lang เป็น $lang ) (
พิมพ์f(
"" ,
$lang [ "ชื่อ" ] ,
$lang -> ปรากฏ ,
$lang -> ผู้สร้าง
) ;
}

สังเกตว่าฉันเข้าถึงชื่อแอตทริบิวต์ lang ขององค์ประกอบเพื่อรับชื่อภาษาได้อย่างไร วิธีนี้คุณสามารถเข้าถึงแอตทริบิวต์ใด ๆ ขององค์ประกอบที่แสดงเป็นวัตถุ SimpleXMLElement

การทำงานกับเนมสเปซ

ในขณะที่ทำงานกับ XML ของบริการเว็บต่างๆ คุณจะพบกับเนมสเปซองค์ประกอบมากกว่าหนึ่งครั้ง มาเปลี่ยนของเรากันเถอะ languages.xmlเพื่อแสดงตัวอย่างการใช้เนมสเปซ:



xmlns:dc =>

> 1972>
> เดนนิส ริตชี่ >
>

> 1995>
> ราสมุส เลอร์ดอร์ฟ >
>

> 1995>
> เจมส์ กอสลิง >
>
>

ตอนนี้องค์ประกอบ ผู้สร้างพอดีกับเนมสเปซ ดีซีซึ่งชี้ไปที่http://purl.org/dc/elements/1.1/ หากคุณพยายามพิมพ์ผู้สร้างภาษาโดยใช้รหัสก่อนหน้าของเรา มันจะไม่ทำงาน ในการอ่านเนมสเปซองค์ประกอบ คุณต้องใช้วิธีใดวิธีหนึ่งต่อไปนี้

วิธีแรกคือการใช้ชื่อ URI โดยตรงในโค้ดเมื่อเข้าถึงเนมสเปซองค์ประกอบ ตัวอย่างต่อไปนี้แสดงวิธีการดำเนินการนี้:

$dc = $ภาษา -> lang [ 1 ] -> เด็ก ๆ( "http://purl.org/dc/elements/1.1/") ;
ก้อง $dc -> ผู้สร้าง ;

วิธี เด็ก()ใช้เนมสเปซและส่งกลับองค์ประกอบลูกที่ขึ้นต้นด้วยคำนำหน้า ต้องใช้สองอาร์กิวเมนต์ ข้อแรกคือเนมสเปซ XML และข้อที่สองคืออาร์กิวเมนต์ทางเลือกซึ่งเป็นค่าเริ่มต้น เท็จ- หากอาร์กิวเมนต์ที่สองถูกตั้งค่าเป็น TRUE เนมสเปซจะถือเป็นคำนำหน้า หากเป็น FALSE เนมสเปซจะถือเป็นเนมสเปซ URL

วิธีที่สองคือการอ่านชื่อ URI จากเอกสารและใช้เมื่อเข้าถึงเนมสเปซองค์ประกอบ นี่เป็นวิธีที่ดีกว่าในการเข้าถึงองค์ประกอบต่างๆ เนื่องจากคุณไม่จำเป็นต้องฮาร์ดโค้ดเป็น URI

$namespaces = $ภาษา -> getNamespaces (จริง) ;
$dc = $ภาษา -> lang [ 1 ] -> เด็ก ( ($เนมสเปซ [ "dc" ] ) ;

ก้อง $dc -> ผู้สร้าง ;

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

ตอนนี้คุณสามารถวนซ้ำรายการภาษาดังนี้:

$ภาษา = simplexml_load_file ("ภาษา.xml" ) ;
$ns = $ภาษา -> getNamespaces (จริง ) ;

foreach ($ภาษา -> lang เป็น $lang ) (
$dc = $lang -> เด็ก ๆ ($ns [ "dc" ] ) ;
พิมพ์f(
"

%s ปรากฏใน %d และถูกสร้างขึ้นโดย %s

" ,
$lang [ "ชื่อ" ] ,
$lang -> ปรากฏ ,
$dc -> ผู้สร้าง
) ;
}

ตัวอย่างการปฏิบัติ - แยกวิเคราะห์ช่องวิดีโอจาก YouTube

ลองดูตัวอย่างที่ได้รับฟีด RSS จาก ช่องยูทูปและแสดงลิงก์ไปยังวิดีโอทั้งหมดจากวิดีโอนั้น เมื่อต้องการทำเช่นนี้ โปรดติดต่อที่อยู่ต่อไปนี้:

http://gdata.youtube.com/feeds/api/users/xxx/uploads

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

  • ลิงค์วิดีโอ
  • จิ๋ว
  • ชื่อ

เราจะเริ่มต้นด้วยการค้นหาและโหลด XML:

$channel = "ชื่อช่อง" ;
$URL = "http://gdata.youtube.com/feeds/api/users/"- $ช่อง. "/อัพโหลด" ;
$xml = file_get_contents($url);

$feed = simplexml_load_string ($xml) ;
$ns = $feed -> getNameSpaces ( จริง ) ;

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

>

>



ชื่อ… >

>

>

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

foreach ($feed -> รายการเป็น $entry ) (
$group = $entry -> เด็ก ๆ ($ns [ "สื่อ" ] ) ;
$กลุ่ม = $กลุ่ม -> กลุ่ม ;
$thumbnail_attrs = $group -> ภาพขนาดย่อ [ 1 ] -> คุณลักษณะ () ;
$image = $thumbnail_attrs [ "url" ] ;
$player = $group -> ผู้เล่น -> คุณสมบัติ () ;
$link = $player [ "url" ] ;
$title = $group -> ชื่อ ;
พิมพ์f( "

" ,
$player, $image, $title);
}

บทสรุป

ตอนนี้คุณรู้วิธีใช้แล้ว SimpleXMLสำหรับการแยกวิเคราะห์ข้อมูล XML คุณสามารถพัฒนาทักษะของคุณได้โดยการแยกวิเคราะห์ฟีด XML ต่างๆ ด้วย API ที่แตกต่างกัน แต่สิ่งสำคัญคือต้องพิจารณาว่า SimpleXML จะอ่าน DOM ทั้งหมดลงในหน่วยความจำ ดังนั้นหากคุณกำลังแยกวิเคราะห์ชุดข้อมูลขนาดใหญ่ หน่วยความจำของคุณอาจไม่เพียงพอ หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับ SimpleXML โปรดอ่านเอกสารประกอบ


หากคุณมีคำถามใด ๆ เราขอแนะนำให้ใช้ของเรา

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

การเลือกพาร์เซอร์

การวิเคราะห์ช่องทาง

ขั้นตอนแรกในการแยกวิเคราะห์ฟีดคือการตัดสินใจว่าคุณสนใจช่องข้อมูลใด parser แยกฟิลด์ที่กำหนดและละเว้นสิ่งอื่นทั้งหมด

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

คำถามใหม่ล่าสุดที่ติดแท็ก android - Stack Overflow ... ... http://stackoverflow.com/q/9439999 0 ไฟล์ข้อมูลของฉันอยู่ที่ไหน? หน้าผา2310 http://stackoverflow.com/users/1128925 2012-02-25T00:30:54Z 2012-02-25T00:30:54Z

ฉันมีแอปพลิเคชันที่ต้องใช้ไฟล์ข้อมูล...

... ...

แอปพลิเคชันตัวอย่างดึงข้อมูลจากแท็กรายการและชื่อแท็กย่อย ลิงก์ และสรุป

การสร้างอินสแตนซ์ตัวแยกวิเคราะห์

ขั้นตอนต่อไปคือการยกตัวอย่าง parser และเริ่มกระบวนการแยกวิเคราะห์ ตัวอย่างนี้เตรียมใช้งาน parser เพื่อไม่ให้จัดการเนมสเปซและใช้ InputStream ที่ให้มาเป็นอินพุต กระบวนการแยกวิเคราะห์เริ่มต้นด้วยการเรียก nextTag() และเรียกใช้เมธอด readFeed() ซึ่งจะดึงและประมวลผลข้อมูลที่แอปพลิเคชันสนใจ:

คลาสสาธารณะ StackOverflowXmlParser ( // เราไม่ได้ใช้เนมสเปซส่วนตัวคงที่สุดท้าย String ns = null; สาธารณะรายการแยกวิเคราะห์ (InputStream ใน) ​​พ่น XmlPullParserException, IOException ( ลอง ( XmlPullParser parser = Xml.newPullParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES , false); parser.setInput(in, null); parser.nextTag(); กลับ readFeed(parser) ในที่สุด ( in.close(); ) ... )

หักช่อง

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

รายการส่วนตัว readFeed(XmlPullParser parser) พ่น XmlPullParserException, IOException ( รายการรายการ = new ArrayList (); parser.require(XmlPullParser.START_TAG, ns, "feed"); while (parser.next() != XmlPullParser.END_TAG) ( ถ้า (parser.getEventType() != XmlPullParser.START_TAG) ( Continue; ) String name = parser.getName(); // เริ่มต้นด้วยการค้นหาแท็กรายการ if (name.equals("entry")) ( entry.add( readEntry(parser)); ) else ( ข้าม(parser); ) ) ส่งคืนรายการ;

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

ขั้นตอนในการแยกวิเคราะห์ฟีด XML มีดังนี้:

ตัวอย่างนี้แสดงให้เห็นว่า Parser แยกวิเคราะห์รายการ ชื่อ ลิงก์ และสรุปอย่างไร

รายการคลาสคงที่สาธารณะ (ชื่อสตริงสุดท้ายสาธารณะ; ลิงก์สตริงสุดท้ายสาธารณะ; สรุปสตริงสุดท้ายสาธารณะ; รายการส่วนตัว (ชื่อสตริง, สรุปสตริง, ลิงก์สตริง) ( this.title = title; this.summary = summary; this.link = link ; ) ) // แยกวิเคราะห์เนื้อหาของรายการ หากพบชื่อเรื่อง สรุป หรือแท็กลิงก์ ให้ส่งต่อ // ไปยังวิธีการ "อ่าน" ที่เกี่ยวข้องเพื่อการประมวลผล มิฉะนั้น ให้ข้ามแท็ก รายการส่วนตัว readEntry(XmlPullParser parser) พ่น XmlPullParserException, IOException ( parser.require(XmlPullParser.START_TAG, ns, "entry"); String title = null; String summary = null; String link = null; while (parser.next() ! = XmlPullParser.END_TAG) ( if (parser.getEventType() != XmlPullParser.START_TAG) ( Continue; ) String name = parser.getName(); if (name.equals("title")) ( title = readTitle(parser) ; ) else if (name.equals("summary")) ( summary = readSummary(parser); ) else if (name.equals("link")) ( link = readLink(parser); ) else ( ข้าม(parser) ; ) ) ส่งคืนรายการใหม่ (ชื่อ, สรุป, ลิงก์) // ประมวลผลแท็กชื่อในฟีด สตริงส่วนตัว readTitle(XmlPullParser parser) พ่น IOException, XmlPullParserException ( parser.require(XmlPullParser.START_TAG, ns, "title"); String title = readText(parser); parser.require(XmlPullParser.END_TAG, ns, "title"); return title; ) // ประมวลผลแท็กลิงก์ในฟีด สตริงส่วนตัว readLink(XmlPullParser parser) พ่น IOException, XmlPullParserException ( String link = ""; parser.require(XmlPullParser.START_TAG, ns, "link"); String tag = parser.getName(); String relType = parser.getAttributeValue(null , "rel"); if (tag.equals("link")) ( if (relType.equals("alternate"))( link = parser.getAttributeValue(null, "href"); parser.nextTag(); ) ) parser.require(XmlPullParser.END_TAG, ns, "link"); return link) // ประมวลผลแท็กสรุปในฟีด สตริงส่วนตัว readSummary(XmlPullParser parser) ส่ง IOException, XmlPullParserException ( parser.require(XmlPullParser.START_TAG, ns, "summary"); String summary = readText(parser); parser.require(XmlPullParser.END_TAG, ns, "summary"); return summary; ) // สำหรับชื่อแท็กและสรุป ให้แยกค่าข้อความออกมา สตริงส่วนตัว readText(XmlPullParser parser) พ่น IOException, XmlPullParserException ( String result = ""; if (parser.next() == XmlPullParser.TEXT) ( result = parser.getText(); parser.nextTag(); ) ส่งคืนผลลัพธ์; ) ... )

ข้ามรายการที่คุณไม่ต้องการ

ในขั้นตอนหนึ่งของการแยกวิเคราะห์ XML ที่อธิบายไว้ข้างต้น parser จะข้ามแท็กที่เราไม่สนใจ ด้านล่างนี้เป็นโค้ดพาร์เซอร์สำหรับวิธีการข้าม ():

ข้ามโมฆะส่วนตัว (XmlPullParser parser) พ่น XmlPullParserException, IOException ( if (parser.getEventType() != XmlPullParser.START_TAG) ( Throw new IllegalStateException(); ) int deep = 1; while (deep != 0) ( switch (parser. ถัดไป()) ( case XmlPullParser.END_TAG: deep--; break; case XmlPullParser.START_TAG: deep++; break; ) ) )

นี่คือวิธีการทำงาน:

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

ดังนั้น หากองค์ประกอบปัจจุบันมีองค์ประกอบที่ซ้อนกัน ค่าความลึกจะไม่เป็น 0 จนกว่าโปรแกรมแยกวิเคราะห์จะประมวลผลเหตุการณ์ทั้งหมดระหว่าง START_TAG ดั้งเดิมและ END_TAG ที่เกี่ยวข้อง ตัวอย่างเช่น พิจารณาว่าเครื่องวิเคราะห์ผ่านไปอย่างไร องค์ประกอบที่มี 2 องค์ประกอบซ้อนกัน และ :

  • ในการผ่านครั้งแรกผ่านลูป while แท็กถัดไปที่เครื่องวิเคราะห์พบหลังจากนั้น นี่คือ START_TAG สำหรับ
  • ในการผ่านครั้งที่สองผ่านลูป while แท็กถัดไปที่เครื่องวิเคราะห์พบคือ END_TAG
  • ในการผ่านครั้งที่สามผ่านลูป while แท็กถัดไปที่เครื่องวิเคราะห์พบคือ START_TAG - ค่าความลึกเพิ่มขึ้นเป็น 2
  • ในการผ่านครั้งที่สี่ผ่านลูป while แท็กถัดไปที่เครื่องวิเคราะห์พบคือ END_TAG- ค่าความลึกจะลดลงเหลือ 1
  • ในการผ่านครั้งที่ห้าซึ่งเป็นครั้งสุดท้ายผ่านลูป while แท็กถัดไปที่เครื่องวิเคราะห์พบคือ END_TAG- ค่าความลึกจะลดลงเหลือ 0 ซึ่งแสดงว่า ข้ามองค์ประกอบสำเร็จแล้ว

การประมวลผลข้อมูลเอ็กซ์เอ็มแอล

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

ในตัวอย่างด้านล่าง เมธอด loadPage() จะดำเนินการดังต่อไปนี้:

  • เริ่มต้นตัวแปรสตริงด้วย URL ที่ชี้ไปยังฟีด XML
  • หากการตั้งค่าผู้ใช้และการเชื่อมต่อเครือข่ายอนุญาต ให้เรียก new DownloadXmlTask().execute(url) สิ่งนี้จะสร้างออบเจ็กต์ DownloadXmlTask ​​​​ใหม่ (คลาสย่อย AsyncTask) และดำเนินการวิธีการดำเนินการ () ซึ่งจะดาวน์โหลดและแยกวิเคราะห์ไปป์และส่งกลับผลลัพธ์สตริงที่จะแสดงใน UI
NetworkActivity ระดับสาธารณะขยายกิจกรรม (สตริงสุดท้ายคงที่สาธารณะ WIFI = "Wi-Fi"; สตริงสุดท้ายคงที่สาธารณะ ANY = "ใด ๆ"; URL สตริงสุดท้ายคงที่ส่วนตัว = "http://stackoverflow.com/feeds/tag?tagnames=android&sort =ใหม่ล่าสุด"; // มีการเชื่อมต่อ Wi-Fi หรือไม่ บูลีนคงที่ส่วนตัว wifiConnected = false; // มีการเชื่อมต่อมือถือหรือไม่ บูลีนคงที่ส่วนตัว mobileConnected = false; // ควรรีเฟรชจอแสดงผลหรือไม่ บูลีนคงที่สาธารณะ RefreshDisplay = true; public static String sPref = null ... // ใช้ AsyncTask เพื่อดาวน์โหลดฟีด XML จาก stackoverflow.com. public void loadPage() ( if((sPref.equals(ANY)) && (wifiConnected || mobileConnected ) ) ( new DownloadXmlTask().execute(URL); ) else if ((sPref.equals(WIFI)) && (wifiConnected)) ( new DownloadXmlTask().execute(URL); ) else ( // แสดงข้อผิดพลาด ) )
  • doInBackground() ดำเนินการเมธอด loadXmlFromNetwork() โดยจะส่ง URL ของช่องเป็นพารามิเตอร์ วิธีการ loadXmlFromNetwork() รับและประมวลผลช่องสัญญาณ เมื่อเสร็จสิ้นการประมวลผล ก็จะส่งกลับสตริงผลลัพธ์
  • onPostExecute() รับสตริงที่ส่งคืนและแสดงใน UI
// การใช้งาน AsyncTask ที่ใช้ในการดาวน์โหลดฟีด XML จาก stackoverflow.com คลาสส่วนตัว DownloadXmlTask ​​ขยาย AsyncTask ( @Override protected String doInBackground(String... urls) ( ลอง ( return loadXmlFromNetwork(urls); ) catch (IOException e) ( return getResources().getString(R.string.connection_error); ) catch (XmlPullParserException e) ( return getResources().getString(R.string.xml_error); ) @Override protected void onPostExecute(String result) ( setContentView(R.layout.main); // แสดงสตริง HTML ใน UI ผ่าน WebView WebView myWebView = ( WebView) findViewById(R.id.webview); myWebView.loadData(ผลลัพธ์, "ข้อความ/html", null) )

ด้านล่างนี้คือเมธอด loadXmlFromNetwork() ซึ่งเรียกจาก DownloadXmlTask มันทำดังต่อไปนี้:

  1. สร้างอินสแตนซ์ของ StackOverflowXmlParser นอกจากนี้ยังสร้างตัวแปรสำหรับออบเจ็กต์รายการ และชื่อ , url และสรุป เพื่อจัดเก็บค่าที่แยกจากฟีด XML สำหรับฟิลด์เหล่านี้
  2. เรียก downloadUrl() ซึ่งจะดาวน์โหลดช่องและส่งกลับเป็น InputStream
  3. ใช้ StackOverflowXmlParser เพื่อแยกวิเคราะห์ InputStream StackOverflowXmlParser เติมข้อมูลในรายการด้วยข้อมูลจากฟีด
  4. ประมวลผลรายการ และรวมข้อมูลช่องเข้ากับมาร์กอัป HTML
  5. ส่งกลับสตริง HTML ที่แสดงใน UI ของกิจกรรมหลัก AsyncTask ในเมธอด onPostExecute()
// อัปโหลด XML จาก stackoverflow.com แยกวิเคราะห์ และรวมเข้ากับ // มาร์กอัป HTML ส่งกลับสตริง HTML สตริงส่วนตัว loadXmlFromNetwork (String urlString) พ่น XmlPullParserException, IOException (InputStream stream = null; // สร้างอินสแตนซ์ parser StackOverflowXmlParser stackOverflowXmlParser = new StackOverflowXmlParser (); List รายการ = โมฆะ;

ชื่อสตริง = null;

URL สตริง = null; สรุปสตริง = null;ปฏิทินทันที = Calendar.getInstance();

ตัวจัดรูปแบบ DateFormat = SimpleDateFormat ใหม่ ("MMM dd h:mmaa");

"); // หากผู้ใช้ตั้งค่ากำหนดให้รวมข้อความสรุป // เพิ่มลงในจอแสดงผล ถ้า (pref) ( htmlString.append(entry.summary); ) ) กลับ htmlString.toString(); ) // กำหนดการแสดงสตริงของ URL ให้ตั้งค่าการเชื่อมต่อและรับ // สตรีมอินพุต ส่วนตัว InputStream downloadUrl (String urlString) พ่น IOException ( URL url = new URL(urlString); HttpURLConnection conn = (HttpURLConnection) url.openConnection() ; conn.setReadTimeout(10,000 /* มิลลิวินาที */); conn.setConnectTimeout(15000 /* มิลลิวินาที */); conn.setRequestMethod("GET"); // เริ่มการสืบค้น conn.connect( ); );
ผู้เขียน : อาร์เซนี คาพูลไคน์
วันที่เผยแพร่: 21 กันยายน 2555
แปล: อ. ภานิน
วันที่แปล: 10 พฤศจิกายน 2556

การแนะนำ

XML เป็นภาษามาร์กอัปมาตรฐานที่ระบุชุดกฎสำหรับการเข้ารหัสเอกสารที่มีโครงสร้างแบบลำดับชั้นในรูปแบบข้อความที่มนุษย์สามารถอ่านได้ มาตรฐาน XML แพร่หลายและใช้เพื่อสร้างทั้งเอกสารธรรมดาที่มีขนาดกะทัดรัดมาก (เช่น คำขอ SOAP) และเอกสารหลายกิกะไบต์ (ใช้โดยโครงการ OpenStreetMap) ที่มีการพึ่งพาข้อมูลที่ซับซ้อน (COLLADA) ในการประมวลผลเอกสาร XML โดยทั่วไปผู้ใช้จำเป็นต้องมีไลบรารีพิเศษ: ต้องใช้ตัวแยกวิเคราะห์เอกสาร XML ที่แปลงเอกสารจากเอกสารต้นฉบับเป็นการนำเสนอภายใน มาตรฐาน XML เป็นการแลกเปลี่ยนในแง่ของความเร็วในการแยกวิเคราะห์ ความสามารถในการอ่านของผู้ใช้ และความซับซ้อนของโค้ดในการแยกวิเคราะห์ ดังนั้น การมีระบบที่รวดเร็วสำหรับการแยกวิเคราะห์เอกสาร XML อาจส่งผลต่อตัวเลือก XML ที่ต้องการเป็นรูปแบบสำหรับการจัดเก็บข้อมูลแอปพลิเคชัน

บทนี้อธิบายเทคนิคต่างๆ ที่มุ่งปรับปรุงประสิทธิภาพของระบบการแยกวิเคราะห์ที่อธิบายไว้ และช่วยให้ผู้เขียนพัฒนาระบบการแยกวิเคราะห์ที่มีประสิทธิผลอย่างมากโดยใช้ภาษาการเขียนโปรแกรม C++: pugixml แม้ว่าเทคนิคเหล่านี้จะใช้สำหรับระบบแยกวิเคราะห์เอกสาร XML แต่ส่วนใหญ่สามารถนำไปใช้ในระบบแยกวิเคราะห์เอกสารในรูปแบบอื่น หรือแม้แต่ในส่วนประกอบซอฟต์แวร์ที่ไม่เกี่ยวข้องโดยสิ้นเชิง (ตัวอย่างเช่น อัลกอริธึมการจัดการหน่วยความจำใช้กันอย่างแพร่หลายในพื้นที่ระบบแยกวิเคราะห์เอกสารข้อความที่ไม่เกี่ยวข้อง) .

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

รูปแบบของระบบการแยกวิเคราะห์ XML

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

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

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

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

โซลูชันทางสถาปัตยกรรมใน pugixml

ในระหว่างการพัฒนาไลบรารี pugixml จุดสนใจส่วนใหญ่อยู่ที่ปัญหาของการสร้างการแสดง DOM เนื่องจากถึงแม้จะมีระบบแยกวิเคราะห์ที่ใช้ SAX ที่รวดเร็วและมีน้ำหนักเบา (เช่น Expat) ก็พร้อมใช้งาน แต่ระบบแยกวิเคราะห์ XML บน DOM ทั้งหมดก็พร้อมใช้งานสำหรับการผลิต การใช้งานในขณะที่สร้าง pugixml (2549) นั้นไม่เบาเกินไปหรือไม่เร็วเกินไป ตามนี้ เป้าหมายหลักของกระบวนการพัฒนา puixml คือการสร้างไลบรารีที่รวดเร็วและมีน้ำหนักเบาสำหรับดำเนินการจัดการเอกสาร XML บน DOM


อนุญาตให้ตีพิมพ์บทความนี้ได้เฉพาะเมื่อมีลิงก์ไปยังเว็บไซต์ของผู้เขียนบทความเท่านั้น

ในบทความนี้ ฉันจะแสดงตัวอย่างวิธีแยกวิเคราะห์ไฟล์ XML ขนาดใหญ่ หากเซิร์ฟเวอร์ของคุณ (โฮสติ้ง) ไม่ได้ห้ามไม่ให้เพิ่มเวลาการทำงานของสคริปต์ คุณสามารถแยกวิเคราะห์ไฟล์ XML ที่มีน้ำหนักอย่างน้อยกิกะไบต์ โดยส่วนตัวแล้วฉันจะแยกวิเคราะห์เฉพาะไฟล์จากโอโซนที่มีน้ำหนัก 450 เมกะไบต์เท่านั้น

เมื่อแยกวิเคราะห์ไฟล์ XML ขนาดใหญ่ เกิดปัญหาสองประการ:
1. หน่วยความจำไม่เพียงพอ
2. มีเวลาจัดสรรไม่เพียงพอสำหรับให้สคริปต์ทำงาน

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

PHP มีตัวเลือกการประมวลผล XML ในตัวมากมาย - SimpleXML, DOM, SAX
ตัวเลือกทั้งหมดเหล่านี้มีการอธิบายโดยละเอียดในบทความหลายบทความพร้อมตัวอย่าง แต่ตัวอย่างทั้งหมดแสดงให้เห็นถึงการทำงานกับเอกสาร XML แบบเต็ม

นี่คือตัวอย่างหนึ่ง รับวัตถุจากไฟล์ XML

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

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

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

ฟังก์ชั่น webi_xml ($ไฟล์)
{

########
### ฟังก์ชั่นข้อมูล

{
พิมพ์ $data ;
}
############################################



{
พิมพ์ $ชื่อ ;
print_r($attrs);
}


## ฟังก์ชั่นแท็กปิด
ฟังก์ชั่น endElement ($parser, $name)
{
พิมพ์ $ชื่อ ;
}
############################################

($xml_parser, "ข้อมูล");

//เปิดไฟล์
$fp = fopen($file, "r");

$perviy_vxod = 1 ; $ข้อมูล = "" ;



{

$simvol = fgetc ($fp); $data .= $simvol ;


if($simvol != ">" ) ( ดำเนินการต่อ;)


เสียงสะท้อน "

หยุดพัก;
}

$ข้อมูล = "" ;
}
fclose($fp);

Webi_xml("1.xml");

?>

ในตัวอย่างนี้ ฉันรวมทุกอย่างไว้ในฟังก์ชันเดียว webi_xml() และที่ด้านล่างสุด คุณจะเห็นการเรียกของมัน
สคริปต์ประกอบด้วยฟังก์ชันหลักสามประการ:
1. ฟังก์ชั่นที่จับการเปิดแท็ก startElement()
2. ฟังก์ชั่นที่จับแท็กปิด endElement()
3. และฟังก์ชั่นการรับ ข้อมูล() .

สมมติว่าเนื้อหาของไฟล์ 1.xml เป็นสูตร



< title >ขนมปังธรรมดา
< ingredient amount = "3" unit = "стакан" >แป้ง
< ingredient amount = "0.25" unit = "грамм" >ยีสต์
< ingredient amount = "1.5" unit = "стакан" >น้ำอุ่น
< ingredient amount = "1" unit = "чайная ложка" >เกลือ
< instructions >
< step > ผสมส่วนผสมทั้งหมดแล้วนวดให้ละเอียด.
< step > คลุมด้วยผ้าแล้วทิ้งไว้หนึ่งชั่วโมงในห้องอุ่น.
< step > นวดอีกครั้ง, วางบนถาดอบแล้วนำเข้าเตาอบ.
< step > เยี่ยมชมเว็บไซต์


เราเริ่มต้นด้วยความท้าทาย ฟังก์ชั่นทั่วไป webi_xml("1.xml");
จากนั้น parser จะเริ่มทำงานในฟังก์ชันนี้และแปลงชื่อแท็กทั้งหมดให้เป็นตัวพิมพ์ใหญ่ เพื่อให้แท็กทั้งหมดมีตัวพิมพ์เหมือนกัน

$xml_parser = xml_parser_create();
xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, จริง);

ตอนนี้เราระบุแล้วว่าฟังก์ชันใดจะทำงานเพื่อจับการเปิดแท็ก การปิด และการประมวลผลข้อมูล

xml_set_element_handler($xml_parser, "startElement", "endElement");
xml_set_Character_data_handler($xml_parser, "ข้อมูล");

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

และส่งไปยังเครื่องถอดประกอบ
xml_parse ($xml_parser, $data, feof ($fp));
หลังจากประมวลผลข้อมูลแล้ว ตัวแปรสตริงจะถูกรีเซ็ต และการรวบรวมข้อมูลลงในสตริงจะเริ่มต้นอีกครั้ง และสตริงจะถูกสร้างขึ้นเป็นครั้งที่สอง

ในวันที่สาม
</b><br>ในวันที่สี่ <br><b>ขนมปังธรรมดา

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

เลอ>ขนมปังธรรมดา
ด้วยวิธีนี้ คุณจะไม่สามารถส่งข้อมูลไปยังตัวจัดการได้ เนื่องจากแท็กขาด
คุณสามารถคิดวิธีการส่งข้อมูลไปยังตัวจัดการของคุณเองได้ เช่น รวบรวมข้อมูล 1 เมกะไบต์ และส่งไปยังตัวจัดการเพื่อเพิ่มความเร็ว เพียงตรวจสอบให้แน่ใจว่าแท็กนั้นสมบูรณ์อยู่เสมอ และข้อมูลสามารถฉีกขาดได้
เรียบง่าย</b><br><b>ขนมปัง

จึงสามารถส่งเป็นอะไหล่ได้ตามใจชอบ ไฟล์ขนาดใหญ่ถึงผู้จัดการ

ตอนนี้เรามาดูวิธีการประมวลผลข้อมูลนี้และวิธีรับข้อมูล

เริ่มต้นด้วยฟังก์ชันแท็กเปิด startElement ($พาร์เซอร์, $ชื่อ, $attrs)
สมมติว่าการประมวลผลถึงบรรทัดแล้ว
< ingredient amount = "3" unit = "стакан" >แป้ง
จากนั้นภายในฟังก์ชัน ตัวแปร $name จะเท่ากับ วัตถุดิบนั่นคือชื่อของแท็กที่เปิดอยู่ (ยังไม่ได้มาปิดแท็ก)
นอกจากนี้ ในกรณีนี้ อาร์เรย์ของแอตทริบิวต์ของแท็ก $attrs จะพร้อมใช้งาน ซึ่งจะมีข้อมูล จำนวน = "3" และหน่วย = "แก้ว".

หลังจากนั้น ฟังก์ชันจะประมวลผลข้อมูลของแท็กที่เปิดอยู่ ข้อมูล ($พาร์เซอร์, $data)
ตัวแปร $data จะมีทุกอย่างที่อยู่ระหว่างแท็กเปิดและแท็กปิด ในกรณีของเราคือข้อความ Muka

และการประมวลผลสตริงของเราโดยฟังก์ชันจะสิ้นสุดลง endElement ($พาร์เซอร์, $ชื่อ)
นี่คือชื่อของแท็กที่ปิด ในกรณีของเรา $name จะเท่ากับ วัตถุดิบ

และหลังจากนั้นทุกอย่างก็กลับเป็นวงกลมอีกครั้ง

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

ฟังก์ชั่น webi_xml ($ไฟล์)
{
$webi_ความลึกทั่วโลก ; // เคาน์เตอร์เพื่อติดตามความลึกของการซ้อน
$เว็บบี_ความลึก = 0 ;
$webi_tag_open ทั่วโลก ; // จะมีอาร์เรย์ของ open in ในขณะนี้แท็ก
$webi_tag_open = array();
$webi_data_temp ทั่วโลก ; // อาร์เรย์นี้จะมีข้อมูลของแท็กเดียว

####################################################
### ฟังก์ชั่นข้อมูล
ข้อมูลฟังก์ชัน ($parser, $data)
{
$webi_ความลึกทั่วโลก ;
$webi_tag_open ทั่วโลก ;
$webi_data_temp ทั่วโลก ;
// เพิ่มข้อมูลลงในอาร์เรย์ที่ระบุการซ้อนและแท็กที่เปิดอยู่ในปัจจุบัน
$webi_data_temp [ $webi_เจาะลึก ][ $webi_tag_open [ $webi_เจาะลึก ]][ "ข้อมูล" ].= $data ;
}
############################################

####################################################
### ฟังก์ชั่นเปิดแท็ก
ฟังก์ชั่น startElement ($parser, $name, $attrs)
{
$webi_ความลึกทั่วโลก ;
$webi_tag_open ทั่วโลก ;
$webi_data_temp ทั่วโลก ;

// หากระดับการซ้อนไม่เป็นศูนย์อีกต่อไป แสดงว่าแท็กหนึ่งเปิดอยู่แล้ว
// และข้อมูลจากข้อมูลนั้นอยู่ในอาร์เรย์แล้ว คุณสามารถประมวลผลได้
ถ้า ($webi_ความลึก)
{




" ;

พิมพ์ "
" ;
print_r($webi_tag_open); // อาร์เรย์ของแท็กที่เปิดอยู่
พิมพ์ "


" ;

// หลังจากประมวลผลข้อมูลแล้ว ให้ลบออกเพื่อเพิ่มหน่วยความจำ
unset($GLOBALS [ "webi_data_temp" ][ $webi_ledge ]);
}

// ขณะนี้แท็กถัดไปถูกเปิดขึ้น และการประมวลผลเพิ่มเติมจะเกิดขึ้นในขั้นตอนถัดไป
$webi_ความลึก++; // เพิ่มการซ้อน

$webi_tag_open [ $webi_ledge ]= $name ; // เพิ่มแท็กเปิดลงในอาร์เรย์ข้อมูล
$webi_data_temp [ $webi_เจาะลึก ][ $name ][ "attrs" ]= $attrs ; // ตอนนี้เพิ่มแอตทริบิวต์แท็ก

}
###############################################

#################################################
## ฟังก์ชั่นแท็กปิด
ฟังก์ชั่น endElement ($parser, $name) (
$webi_ความลึกทั่วโลก ;
$webi_tag_open ทั่วโลก ;
$webi_data_temp ทั่วโลก ;

// การประมวลผลข้อมูลเริ่มต้นที่นี่ เช่น การเพิ่มฐานข้อมูล บันทึกลงในไฟล์ เป็นต้น
// $webi_tag_open ประกอบด้วยแท็กที่เปิดต่อเนื่องกันตามระดับการซ้อน
// ตัวอย่างเช่น $webi_tag_open[$webi_ledge] มีชื่อของแท็กที่เปิดซึ่งข้อมูลกำลังถูกประมวลผลอยู่
// ระดับการซ้อนแท็ก $webi_deep
// $webi_data_temp[$webi_length][$webi_tag_open[$webi_ allowance]]["attrs"] อาร์เรย์ของแอตทริบิวต์ของแท็ก
// $webi_data_temp[$webi_length][$webi_tag_open[$webi_ allowance]]["data"] ข้อมูลแท็ก

พิมพ์ "ข้อมูล" . $webi_tag_open [ $webi_ความลึก ]. "--" .($webi_data_temp [ $webi_เจาะลึก ][ $webi_tag_open [ $webi_เจาะลึก ]][ "ข้อมูล" ]) -
" ;
print_r ($webi_data_temp [ $webi_เจาะลึก ][ $webi_tag_open [ $webi_เจาะลึก ]][ "attrs" ]);
พิมพ์ "
" ;
print_r($webi_tag_open);
พิมพ์ "


" ;

ยกเลิกการตั้งค่า($GLOBALS [ "webi_data_temp" ]); // หลังจากประมวลผลข้อมูลแล้ว เราจะลบอาร์เรย์ที่มีข้อมูลทั้งหมด เนื่องจากแท็กถูกปิด
unset($GLOBALS [ "webi_tag_open" ][ $webi_ledge ]); // ลบข้อมูลเกี่ยวกับแท็กที่เปิดนี้... เนื่องจากปิดไปแล้ว

$webi_ความลึก --; //ลดการซ้อน
}
############################################

$xml_parser = xml_parser_create();
xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, จริง);

// ระบุว่าฟังก์ชันใดจะทำงานเมื่อเปิดและปิดแท็ก
xml_set_element_handler($xml_parser, "startElement", "endElement");

// ระบุฟังก์ชันสำหรับการทำงานกับข้อมูล
xml_set_Character_data_handler($xml_parser, "ข้อมูล");

//เปิดไฟล์
$fp = fopen($file, "r");

$perviy_vxod = 1 ; // ตั้งค่าสถานะเพื่อตรวจสอบรายการแรกในไฟล์
$ข้อมูล = "" ; // ที่นี่เรารวบรวมข้อมูลจากไฟล์เป็นส่วนๆ และส่งไปยังตัวแยกวิเคราะห์ xml

// วนซ้ำจนกว่าจะพบจุดสิ้นสุดของไฟล์
ในขณะที่ (! feof ($fp ) และ $fp )
{
$simvol = fgetc ($fp); // อ่านอักขระหนึ่งตัวจากไฟล์
$data .= $simvol ; // เพิ่มอักขระนี้ในข้อมูลที่จะส่ง

// หากอักขระไม่ใช่แท็กปิด ให้กลับไปที่จุดเริ่มต้นของลูปและเพิ่มอักขระอื่นลงในข้อมูล ไปเรื่อยๆ จนกว่าจะพบแท็กปิดท้าย
if($simvol != ">" ) ( ดำเนินการต่อ;)
// หากพบแท็กปิด ตอนนี้เราจะส่งข้อมูลที่รวบรวมนี้ไปประมวลผล

// ตรวจสอบว่านี่เป็นรายการแรกในไฟล์หรือไม่ จากนั้นเราจะลบทุกอย่างที่อยู่หน้าแท็ก// เนื่องจากบางครั้งคุณอาจพบขยะก่อนที่จะเริ่ม XML (ตัวแก้ไขที่งุ่มง่ามหรือสคริปต์ได้รับไฟล์จากเซิร์ฟเวอร์อื่น)
if($perviy_vxod ) ( $data = strstr ($data , "

// ตอนนี้โยนข้อมูลลงในตัวแยกวิเคราะห์ xml
ถ้า (! xml_parse ($xml_parser, $data, feof ($fp))) (

// ที่นี่คุณสามารถประมวลผลและรับข้อผิดพลาดด้านความถูกต้องได้...
// ทันทีที่พบข้อผิดพลาด การแยกวิเคราะห์จะหยุดลง
เสียงสะท้อน "
ข้อผิดพลาด XML: " . xml_error_string(xml_get_error_code($xml_parser));
echo "ที่บรรทัด" . xml_get_current_line_number ($xml_parser);
หยุดพัก;
}

// หลังจากแยกวิเคราะห์แล้ว ให้ละทิ้งข้อมูลที่รวบรวมไว้สำหรับขั้นตอนถัดไปของวงจร
$ข้อมูล = "" ;
}
fclose($fp);
xml_parser_free($xml_parser);
// ลบตัวแปรโกลบอล
unset($GLOBALS [ "webi_deep" ]);
unset($GLOBALS [ "webi_tag_open" ]);
unset($GLOBALS [ "webi_data_temp" ]);

Webi_xml("1.xml");

?>

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

เพียงเท่านี้ตอนนี้ก็มีหน่วยความจำเพียงพอสำหรับการประมวลผลไฟล์ทุกขนาด แต่เวลาทำงานของสคริปต์สามารถเพิ่มขึ้นได้หลายวิธี
แทรกฟังก์ชันที่จุดเริ่มต้นของสคริปต์
set_time_limit (6000);
หรือ
ini_set ("max_execution_time" , "6000" );

หรือเพิ่มข้อความลงในไฟล์ .htaccess
php_value สูงสุด_execution_time 6000

ตัวอย่างเหล่านี้จะเพิ่มเวลาการทำงานของสคริปต์เป็น 6000 วินาที
คุณสามารถเพิ่มเวลาได้ด้วยวิธีนี้เฉพาะเมื่อปิดเซฟโหมดเท่านั้น

หากคุณมีสิทธิ์เข้าถึงการแก้ไข php.ini คุณสามารถเพิ่มเวลาได้
สูงสุด_execution_time = 6000

ตัวอย่างเช่น บนโฮสติ้ง Masterhost ในขณะที่เขียนบทความนี้ แม้จะห้ามการเพิ่มเวลาสคริปต์ก็ตาม เซฟโหมดแต่ถ้าคุณเป็นมืออาชีพ คุณสามารถสร้าง php build ของคุณเองบน masterhost ได้ แต่นั่นไม่ได้อยู่ในบทความนี้