การแยกวิเคราะห์ XML หมายถึงการผ่านเอกสาร XML และส่งคืนข้อมูลที่เกี่ยวข้อง แม้ว่าบริการเว็บจำนวนมากขึ้นจะส่งคืนข้อมูลในรูปแบบ JSON แต่ส่วนใหญ่ยังคงใช้ XML อยู่ ดังนั้นจึงเป็นเรื่องสำคัญที่จะต้องแยกวิเคราะห์ XML หลัก หากคุณต้องการใช้ API ที่มีอยู่อย่างเต็มรูปแบบ
การใช้นามสกุล SimpleXMLใน PHP ซึ่งถูกเพิ่มกลับเข้ามาใน PHP 5.0 การทำงานกับ XML นั้นง่ายและสะดวกมาก ในบทความนี้ฉันจะแสดงวิธีการทำ
พื้นฐานการใช้งาน
มาเริ่มกันด้วยตัวอย่างต่อไปนี้ ภาษา.xml:
>
>
>
>
เอกสาร XML นี้ประกอบด้วยรายการภาษาโปรแกรมพร้อมข้อมูลบางอย่างเกี่ยวกับแต่ละภาษา: ปีที่ดำเนินการและชื่อผู้สร้าง
ขั้นตอนแรกคือการโหลด XML โดยใช้ฟังก์ชั่นอย่างใดอย่างหนึ่ง simplexml_load_file(), หรือ simplexml_load_string(). ตามชื่อของฟังก์ชัน อันแรกจะโหลด XML จากไฟล์ และอันที่สองจะโหลด XML จากสตริง
ทั้งสองฟังก์ชันอ่านแผนผัง DOM ทั้งหมดลงในหน่วยความจำและส่งคืนอ็อบเจ็กต์ SimpleXMLElement. ในตัวอย่างข้างต้น ออบเจ็กต์ถูกเก็บไว้ในตัวแปรภาษา $ คุณสามารถใช้ฟังก์ชั่น var_dump()หรือ print_r()เพื่อรับข้อมูลโดยละเอียดเกี่ยวกับวัตถุที่ส่งคืน หากคุณต้องการ
SimpleXMLElement วัตถุ
[lang] => Array
[ 0 ] => SimpleXMLElementObject
[@attributes] => Array
[ชื่อ] => C
[ปรากฏตัว] => 1972
[ ผู้สร้าง] => Dennis Ritchie
[ 1 ] => SimpleXMLElement Object
[@attributes] => Array
[ชื่อ] => PHP
[ปรากฏ] => 1995
[ ผู้สร้าง] => ราสมุส เลอร์ดอร์ฟ
[ 2 ] => SimpleXMLElement Object
[@attributes] => Array
[name] => Java
[ปรากฏ] => 1995
[ ผู้สร้าง] => เจมส์ กอสลิง
)
)
XML นี้มีองค์ประกอบราก ภาษาซึ่งมีสามองค์ประกอบ แลงแต่ละองค์ประกอบอาร์เรย์สอดคล้องกับองค์ประกอบ ภาษาในเอกสาร XML
คุณสามารถเข้าถึงคุณสมบัติของวัตถุโดยใช้ตัวดำเนินการ -> . ตัวอย่างเช่น $languages->lang จะส่งคืนวัตถุ SimpleXMLElement ที่ตรงกับองค์ประกอบแรก ภาษา. วัตถุนี้มีสองคุณสมบัติ: ปรากฏและผู้สร้าง
$languages -> lang [ 0 ] -> ปรากฏ ;
$languages -> lang [ 0 ] -> ผู้สร้าง ;
แสดงรายการภาษาและแสดงคุณสมบัติของมันง่ายมากด้วยลูปมาตรฐานเช่น แต่ละ.
foreach ($languages -> lang as $lang ) (
พิมพ์f(
""
,
$lang["name"] ,
$lang -> ปรากฏ ,
$lang -> ผู้สร้าง
)
;
}
สังเกตว่าฉันเข้าถึงชื่อแอตทริบิวต์ขององค์ประกอบ lang เพื่อรับชื่อภาษาได้อย่างไร วิธีนี้คุณสามารถเข้าถึงแอตทริบิวต์ขององค์ประกอบที่แสดงเป็นวัตถุ SimpleXMLElement
การทำงานกับเนมสเปซ
ในขณะที่ทำงานกับ XML ของบริการเว็บต่างๆ คุณมักจะพบเนมสเปซขององค์ประกอบ มาเปลี่ยนของเรากันเถอะ ภาษา.xmlเพื่อแสดงตัวอย่างการใช้เนมสเปซ:
xmlns:dc =>
>
>
>
ตอนนี้องค์ประกอบ ผู้สร้างวางไว้ในเนมสเปซ กระแสตรงซึ่งชี้ไปที่ http://purl.org/dc/elements/1.1/ หากคุณพยายามพิมพ์ผู้สร้างภาษาโดยใช้รหัสก่อนหน้าของเรา จะไม่ทำงาน ในการอ่านเนมสเปซขององค์ประกอบ คุณต้องใช้วิธีใดวิธีหนึ่งต่อไปนี้
วิธีแรกคือการใช้ชื่อ URI โดยตรงในโค้ดเมื่ออ้างถึงเนมสเปซขององค์ประกอบ ตัวอย่างต่อไปนี้แสดงวิธีการดำเนินการนี้:
$dc = $languages -> lang [ 1 ] -> เด็ก ( "http://purl.org/dc/elements/1.1/")
;
echo $dc -> ผู้สร้าง ;
วิธี เด็ก()ใช้เนมสเปซและส่งคืนองค์ประกอบย่อยที่ขึ้นต้นด้วยคำนำหน้า ต้องใช้สองอาร์กิวเมนต์ อันแรกคือเนมสเปซ XML และอาร์กิวเมนต์ที่สองเป็นอาร์กิวเมนต์ทางเลือกที่มีค่าเริ่มต้นเป็น เท็จ. ถ้าอาร์กิวเมนต์ที่สองถูกตั้งค่าเป็น TRUE เนมสเปซจะถือเป็นคำนำหน้า หากเป็น FALSE เนมสเปซจะถือเป็นเนมสเปซ URL
วิธีที่สองคืออ่านชื่อ URI จากเอกสารและใช้เมื่ออ้างถึงเนมสเปซขององค์ประกอบ นี่เป็นวิธีที่ดีที่สุดในการเข้าถึงองค์ประกอบ เพราะคุณไม่จำเป็นต้องฮาร์ดโค้ดลงใน URI
$namespaces = $languages -> getNamespaces (จริง) ;
$dc = $languages -> lang [ 1 ] -> children ($namespaces [ "dc" ] ) ;
echo $dc -> ผู้สร้าง ;
วิธี รับเนมสเปซ ()ส่งคืนอาร์เรย์ของชื่อนำหน้าและ URI ที่เกี่ยวข้อง ใช้พารามิเตอร์เพิ่มเติมซึ่งมีค่าเริ่มต้นเป็น เท็จ. หากคุณติดตั้งเช่น จริงจากนั้นเมธอดนี้จะส่งคืนชื่อที่ใช้ในโหนดหลักและโหนดย่อย มิฉะนั้น จะพบเนมสเปซที่ใช้ในโหนดหลักเท่านั้น
ตอนนี้คุณสามารถทำซ้ำผ่านรายการภาษาดังนี้:
$languages = simplexml_load_file ("languages.xml" );
$ns = $languages -> getNamespaces (จริง) ;
foreach ($languages -> lang as $lang ) (
$dc = $lang -> ลูก ($ns [ "dc" ] );
พิมพ์f(
"
%s ปรากฏใน %d และถูกสร้างขึ้นโดย %s
" ,$lang["name"] ,
$lang -> ปรากฏ ,
$dc -> ผู้สร้าง
) ;
}
กรณีศึกษา - การแยกวิเคราะห์ช่องวิดีโอ YouTube
มาดูตัวอย่างที่ได้รับฟีด RSS จากช่อง YouTube และแสดงลิงก์ไปยังวิดีโอทั้งหมดจากช่องดังกล่าว โปรดติดต่อตามที่อยู่ต่อไปนี้:
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 คุณจะเห็นว่ามีองค์ประกอบหลายอย่าง นิติบุคคลซึ่งแต่ละรายการจะเก็บข้อมูลโดยละเอียดเกี่ยวกับวิดีโอเฉพาะจากช่อง แต่เราใช้เฉพาะภาพขนาดย่อ ที่อยู่วิดีโอ และชื่อเท่านั้น องค์ประกอบทั้งสามนี้เป็นลูกขององค์ประกอบ กลุ่มซึ่งเป็นลูกของ รายการ:
…
…
…
>
…
เราจะผ่านทุกองค์ประกอบ รายการและดึงข้อมูลที่จำเป็นสำหรับแต่ละรายการ สังเกตว่า ผู้เล่น, รูปขนาดย่อและ ชื่ออยู่ในเนมสเปซสื่อ ดังนั้นเราต้องดำเนินการตามตัวอย่างที่แล้ว เราได้รับชื่อจากเอกสารและใช้เนมสเปซเมื่ออ้างถึงองค์ประกอบ
foreach ($feed -> รายการเป็น $entry ) (
$group = $entry -> เด็ก ($ns [ "media" ] );
$group = $group -> กลุ่ม ;
$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 XML เป็นรูปแบบสำหรับการแลกเปลี่ยนข้อมูลระหว่างไซต์ มันคล้ายกับ HTML มาก มีเพียง XML ที่อนุญาตให้แท็กและแอตทริบิวต์ของตัวเอง
เหตุใด XML จึงจำเป็นสำหรับการแยกวิเคราะห์ บางครั้งมันเกิดขึ้นที่ไซต์ที่คุณต้องการแยกวิเคราะห์มี API ที่ช่วยให้คุณได้รับสิ่งที่คุณต้องการโดยไม่ต้องใช้ความพยายามมาก ดังนั้น แนะนำให้ทันที - ก่อนแยกวิเคราะห์ไซต์ ให้ตรวจสอบว่ามี API หรือไม่
API คืออะไร? นี่คือชุดของฟังก์ชันที่คุณสามารถส่งคำขอไปยังไซต์นี้และรับการตอบกลับที่ต้องการ คำตอบนี้มักมาในรูปแบบ XML มาเริ่มศึกษากันเลยดีกว่า
การทำงานกับ XML ใน PHP
สมมติว่าคุณมี XML อาจเป็นสตริง เก็บไว้ในไฟล์ หรือให้บริการตามคำขอไปยัง URL เฉพาะ
ให้ XML ถูกเก็บไว้ในสตริง ในกรณีนี้ คุณต้องสร้างวัตถุจากบรรทัดนี้โดยใช้ ใหม่ SimpleXMLElement:
$str = "
ตอนนี้เรามีในตัวแปร $xmlวัตถุที่มีการแยกวิเคราะห์ XML จะถูกเก็บไว้ โดยการเข้าถึงคุณสมบัติของอ็อบเจ็กต์นี้ คุณจะสามารถเข้าถึงเนื้อหาของแท็ก XML ได้ เป็นอย่างไร - เราจะวิเคราะห์ให้ต่ำลงเล็กน้อย
หาก XML ถูกเก็บไว้ในไฟล์หรือส่งคืนโดยการเข้าถึง URL (ซึ่งส่วนใหญ่มักเป็นกรณี) คุณควรใช้ฟังก์ชัน simplexml_load_fileซึ่งทำให้วัตถุเดียวกัน $xml:
$xml = simplexml_load_file (พาธไฟล์หรือ url);
วิธีการทำงาน
ในตัวอย่างด้านล่าง XML ของเราถูกจัดเก็บไว้ในไฟล์หรือ URL
ให้ XML ต่อไปนี้ได้รับ:
มาดูชื่อ อายุ และเงินเดือนของพนักงานกัน:
$xml = simplexml_load_file (พาธไฟล์หรือ url); echo $xml->ชื่อ; //แสดง "Kolya" echo $xml->age; //ผลลัพธ์ 25 echo $xml->เงินเดือน; // เอาต์พุต 1,000
อย่างที่คุณเห็น ออบเจ็กต์ $xml มีคุณสมบัติที่สอดคล้องกับแท็ก
คุณอาจสังเกตเห็นว่าแท็ก
$xml = simplexml_load_file (พาธไฟล์หรือ url); echo $xml->ชื่อ; //แสดง "Kolya" echo $xml->age; //ผลลัพธ์ 25 echo $xml->เงินเดือน; // เอาต์พุต 1,000
XML สามารถมีแท็กรูทได้เพียงแท็กเดียว เช่นเดียวกับแท็กรูท ใน HTML ธรรมดา
มาแก้ไข XML ของเราสักหน่อย:
ในกรณีนี้ เราได้รับสายของการโทร:
$xml = simplexml_load_file (พาธไฟล์หรือ url); echo $xml->worker->name; //แสดง "Kolya" echo $xml->worker->age; //เอาต์พุต 25 echo $xml->worker->เงินเดือน; // เอาต์พุต 1,000
การทำงานกับคุณสมบัติ
ให้ข้อมูลบางส่วนถูกเก็บไว้ในแอตทริบิวต์:
$xml = simplexml_load_file (พาธไฟล์หรือ url); echo $xml->worker["name"]; //แสดง "Kolya" echo $xml->worker["age"]; //เอาต์พุต 25 echo $xml->worker["salary"]; //เอาต์พุต 1,000 echo $xml->worker; // พิมพ์ "หมายเลข 1"
แท็กที่มีขีดกลาง
ใน XML อนุญาตให้ใช้แท็ก (และแอตทริบิวต์) ที่มียัติภังค์ ในกรณีนี้ แท็กดังกล่าวสามารถเข้าถึงได้ดังนี้:
$xml = simplexml_load_file (พาธไฟล์หรือ url); echo $xml->worker->(ชื่อจริง); //แสดง "Kolya" echo $xml->worker->(นามสกุล); // แสดง "Ivanov"
วนซ้ำ
ให้ตอนนี้เราไม่มีคนงานคนเดียว แต่มีหลายคน ในกรณีนี้ เราสามารถวนซ้ำวัตถุของเราด้วย foreach loop:
$xml = simplexml_load_file (พาธไฟล์หรือ url); foreach ($xml เป็น $worker) ( echo $worker->name; // พิมพ์ "Kolya", "Vasya", "Petya" )
จากอ็อบเจ็กต์เป็นอาร์เรย์ปกติ
หากคุณรู้สึกไม่สบายใจในการทำงานกับอ็อบเจ็กต์ คุณสามารถแปลงอ็อบเจ็กต์เป็นอาร์เรย์ PHP ปกติได้โดยใช้เคล็ดลับต่อไปนี้:
$xml = simplexml_load_file (พาธไฟล์หรือ url); var_dump(json_decode(json_encode($xml) จริง));
ข้อมูลมากกว่านี้
การแยกวิเคราะห์ตาม sitemap.xml
บ่อยครั้ง ไซต์มีไฟล์ sitemap.xml ไฟล์นี้เก็บลิงก์ไปยังทุกหน้าของเว็บไซต์เพื่อความสะดวกในการจัดทำดัชนีโดยเครื่องมือค้นหา (อันที่จริงการจัดทำดัชนีคือการแยกวิเคราะห์เว็บไซต์โดย Yandex และ Google)
โดยทั่วไป เราไม่ควรสนใจมากว่าทำไมไฟล์นี้ถึงต้องการ สิ่งสำคัญคือถ้ามีอยู่ คุณไม่สามารถปีนหน้าเว็บไซต์ด้วยวิธีการที่ยุ่งยากใดๆ ได้ แต่เพียงแค่ใช้ไฟล์นี้
วิธีตรวจสอบการมีอยู่ของไฟล์นี้: แยกวิเคราะห์เว็บไซต์ site.ru จากนั้นอ้างอิงถึง site.ru/sitemap.xml ในเบราว์เซอร์ - หากคุณเห็นบางสิ่ง แสดงว่าไฟล์นั้นอยู่ที่นั่น และหากคุณไม่เห็น อนิจจา
หากมีแผนผังเว็บไซต์ แสดงว่ามีลิงก์ไปยังหน้าทั้งหมดของเว็บไซต์ในรูปแบบ XML อย่าลังเลที่จะใช้ XML นี้ แยกวิเคราะห์ แยกลิงก์ไปยังหน้าที่คุณต้องการในทางที่สะดวกสำหรับคุณ (เช่น โดยการแยกวิเคราะห์ URL ที่อธิบายไว้ในวิธีสไปเดอร์)
ด้วยเหตุนี้ คุณจะได้รับรายการลิงก์สำหรับการแยกวิเคราะห์ เหลือเพียงไปที่ลิงก์เหล่านั้นและแยกวิเคราะห์เนื้อหาที่คุณต้องการ
อ่านเพิ่มเติมเกี่ยวกับอุปกรณ์ sitemap.xml ในวิกิพีเดีย
คุณจะทำอย่างไรต่อไป:
เริ่มแก้ปัญหาได้ที่ลิงค์ต่อไปนี้ งานสำหรับบทเรียน
เมื่อตัดสินใจทุกอย่างแล้ว - ไปศึกษาหัวข้อใหม่
อนุญาตให้เผยแพร่บทความนี้โดยมีลิงก์ไปยังเว็บไซต์ของผู้เขียนบทความเท่านั้น
ในบทความนี้ ผมจะแสดงตัวอย่างวิธีแยกวิเคราะห์ไฟล์ XML ขนาดใหญ่ หากเซิร์ฟเวอร์ของคุณ (โฮสติ้ง) ไม่ได้ถูกห้ามไม่ให้เพิ่มเวลาทำงานของสคริปต์ คุณสามารถแยกวิเคราะห์ไฟล์ XML ที่มีน้ำหนักอย่างน้อยกิกะไบต์ โดยส่วนตัวแล้วฉันแยกวิเคราะห์เฉพาะไฟล์จากโอโซนที่มีน้ำหนัก 450 เมกะไบต์
มีปัญหาสองประการเมื่อแยกวิเคราะห์ไฟล์ XML ขนาดใหญ่:
1. หน่วยความจำไม่เพียงพอ
2. มีเวลาจัดสรรไม่เพียงพอสำหรับสคริปต์ในการทำงาน
ปัญหาที่สองเกี่ยวกับเวลาสามารถแก้ไขได้หากเซิร์ฟเวอร์ไม่ได้ห้าม
แต่ปัญหาของหน่วยความจำนั้นแก้ไขได้ยาก แม้ว่าเรากำลังพูดถึงเซิร์ฟเวอร์ของคุณเอง การย้ายไฟล์ขนาด 500 เมกะไบต์นั้นไม่ใช่เรื่องง่าย และแม้แต่ในโฮสติ้งและบน VDS คุณก็ไม่สามารถเพิ่มหน่วยความจำได้
PHP มีตัวเลือกการประมวลผล XML ในตัวหลายตัว - SimpleXML, DOM, SAX
ตัวเลือกทั้งหมดนี้มีรายละเอียดอยู่ในบทความตัวอย่างมากมาย แต่ตัวอย่างทั้งหมดแสดงวิธีการทำงานกับเอกสาร XML ฉบับสมบูรณ์
นี่คือตัวอย่างหนึ่ง เราได้วัตถุจากไฟล์ XML
$xml = simplexml_load_file ("1.xml" ); ?>
ตอนนี้คุณสามารถประมวลผลวัตถุนี้ แต่...
อย่างที่คุณเห็น ไฟล์ XML ทั้งหมดจะถูกอ่านในหน่วยความจำ จากนั้นทุกอย่างจะถูกแยกวิเคราะห์เป็นวัตถุ
นั่นคือ ข้อมูลทั้งหมดเข้าสู่หน่วยความจำ และหากหน่วยความจำที่จัดสรรไม่เพียงพอ สคริปต์จะหยุดทำงาน
ตัวเลือกนี้ไม่เหมาะสำหรับการประมวลผลไฟล์ขนาดใหญ่ คุณต้องอ่านไฟล์ทีละบรรทัดและประมวลผลข้อมูลนี้ตามลำดับ
ในเวลาเดียวกัน การตรวจสอบความถูกต้องก็ถูกดำเนินการเช่นกันในขณะที่ข้อมูลมีการประมวลผล ดังนั้นคุณจะต้องสามารถย้อนกลับได้ เช่น ลบฐานข้อมูลทั้งหมดที่ป้อนในกรณีของไฟล์ XML ที่ไม่ถูกต้อง หรือทำผ่านสองครั้ง ผ่านไฟล์ อ่านเพื่อความถูกต้องก่อน จากนั้นอ่านเพื่อประมวลผลข้อมูล
นี่คือตัวอย่างทางทฤษฎีของการแยกวิเคราะห์ไฟล์ XML ขนาดใหญ่
สคริปต์นี้อ่านอักขระหนึ่งตัวจากไฟล์ รวบรวมข้อมูลนี้ลงในบล็อก และส่งไปยังตัวแยกวิเคราะห์ XML
วิธีนี้ช่วยแก้ปัญหาหน่วยความจำได้อย่างสมบูรณ์และไม่ก่อให้เกิดการโหลด แต่จะทำให้ปัญหารุนแรงขึ้นเมื่อเวลาผ่านไป วิธีพยายามแก้ปัญหาเมื่อเวลาผ่านไปอ่านด้านล่าง
ฟังก์ชัน webi_xml($file)
{
########
### ฟังก์ชั่นการจัดการข้อมูล
{
พิมพ์ $data ;
}
############################################
{
พิมพ์ $name ;
print_r($attrs);
}
## ฟังก์ชั่นปิดแท็ก
ฟังก์ชั่น endElement ($parser , $name )
{
พิมพ์ $name ;
}
############################################
($xml_parser , "ข้อมูล" );
// เปิดไฟล์
$fp = fopen($file , "r" );
$perviy_vxod = 1 ; $data = "" ;
{
$simvol = fgetc($fp); $data .= $simvol ;
if($simvol != ">" ) ( ทำต่อ;)
"
);
$perviy_vxod
=
0
;}
เสียงสะท้อน "
หยุดพัก;
}
$data = "" ;
}
fclose($fp);
webi_xml("1.xml");
?>
ในตัวอย่างนี้ ฉันใส่ทุกอย่างลงในฟังก์ชัน webi_xml () เดียว และการเรียกของฟังก์ชันนี้จะมองเห็นได้ที่ด้านล่างสุด
ตัวสคริปต์เองประกอบด้วยสามหน้าที่หลัก:
1. ฟังก์ชั่นที่จับการเปิดแท็ก startElement()
2. ฟังก์ชั่นที่จับการปิดของ endElement() tag
3. และฟังก์ชั่นการรับข้อมูล data()
สมมติว่าเนื้อหาของไฟล์ 1.xml เป็นสูตรบางอย่าง
<
title
>ขนมปังง่ายๆ
title
>
<
ingredient amount
=
"3"
unit
=
"стакан"
>แป้ง
ingredient
>
<
ingredient amount
=
"0.25"
unit
=
"грамм"
>ยีสต์
ingredient
>
<
ingredient amount
=
"1.5"
unit
=
"стакан"
>น้ำอุ่น
ingredient
>
<
ingredient amount
=
"1"
unit
=
"чайная ложка"
>เกลือ
ingredient
>
<
instructions
>
<
step
>
ผสมส่วนผสมทั้งหมดแล้วนวดให้ละเอียด.
step
>
<
step
>
คลุมด้วยผ้าแล้วทิ้งไว้ในห้องอุ่นเป็นเวลาหนึ่งชั่วโมง.
step
>
<
step
>
นวดอีกครั้ง,
วางถาดอบแล้วเข้าเตาอบ.
step
>
<
step
>
เยี่ยมชมเว็บไซต์
step
>
instructions
>
recipe
>
เราเริ่มต้นด้วยการเรียกใช้ฟังก์ชันทั่วไป 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 ควรเริ่มต้นด้วย
ครั้งแรกที่ตัวแปรสตริงจะรวบรวมสตริง
แล้วส่งไปที่ parser
xml_parse ($xml_parser , $data , feof ($fp ));
หลังจากประมวลผลข้อมูลแล้ว ตัวแปรสตริงจะถูกรีเซ็ต และการรวบรวมข้อมูลในสตริงจะเริ่มต้นอีกครั้งและสตริงจะถูกสร้างขึ้นเป็นครั้งที่สอง
ในครั้งที่สาม
ในที่สี่
ขนมปังง่ายๆ
โปรดทราบว่าตัวแปรสตริงจะถูกสร้างขึ้นโดย tag ที่สมบูรณ์เสมอ >
และไม่จำเป็นต้องส่งแท็กเปิดและปิดพร้อมข้อมูลไปยังตัวแยกส่วน ตัวอย่างเช่น
มันเป็นสิ่งสำคัญสำหรับตัวจัดการนี้ที่จะได้รับแท็กที่ไม่เสียหายทั้งหมดอย่างน้อยหนึ่งแท็กที่เปิดอยู่และในขั้นตอนต่อไปแท็กปิดหรือได้รับไฟล์ 1,000 บรรทัดทันทีไม่สำคัญ สิ่งสำคัญคือแท็ก ไม่แตกหัก ตัวอย่างเช่น
le>ขนมปังง่ายๆ
ดังนั้นจึงเป็นไปไม่ได้ที่จะส่งข้อมูลไปยังตัวจัดการ เนื่องจากแท็กเสีย
คุณสามารถคิดวิธีการส่งข้อมูลไปยังตัวจัดการของคุณเองได้ เช่น รวบรวมข้อมูล 1 เมกะไบต์แล้วส่งไปยังตัวจัดการเพื่อเพิ่มความเร็ว เพียงตรวจสอบให้แน่ใจว่าแท็กสิ้นสุดเสมอและข้อมูลอาจเสียหายได้
ขนมปัง
ดังนั้นคุณสามารถส่งไฟล์ขนาดใหญ่ไปยังตัวจัดการได้ในส่วนต่าง ๆ ตามที่คุณต้องการ
ตอนนี้เรามาดูกันว่าข้อมูลนี้ได้รับการประมวลผลอย่างไรและจะได้รับอย่างไร
เริ่มด้วยฟีเจอร์แท็กเปิด startElement ($parser , $name , $attrs )
สมมติว่าการประมวลผลมาถึงเส้นแล้ว
<
ingredient amount
=
"3"
unit
=
"стакан"
>แป้ง
ingredient
>
จากนั้นภายในฟังก์ชันตัวแปร $name จะเท่ากับ วัตถุดิบนั่นคือชื่อของแท็กเปิด (เรื่องยังไม่ถึงการปิดแท็ก)
นอกจากนี้ ในกรณีนี้ จะมีอาร์เรย์แอตทริบิวต์ของแท็ก $attrs ซึ่งจะมี data จำนวน = "3" และหน่วย = "แก้ว".
หลังจากนั้น ข้อมูลของแท็กเปิดจะถูกประมวลผลโดยฟังก์ชัน ข้อมูล ($ parser , $data )
ตัวแปร $data จะมีทุกอย่างที่อยู่ระหว่างแท็กเปิดและแท็กปิด ในกรณีของเราคือข้อความ Muk
และการประมวลผลสตริงของเราโดยฟังก์ชันก็เสร็จสิ้น endElement ($parser , $name )
นี่คือชื่อแท็กปิด ในกรณีของเรา $name จะเท่ากับ วัตถุดิบ
และหลังจากนั้น ทุกอย่างก็กลับมาเต็มวงอีกครั้ง
ตัวอย่างข้างต้นแสดงให้เห็นถึงหลักการของการประมวลผล XML เท่านั้น แต่สำหรับแอปพลิเคชันจริงจำเป็นต้องได้รับการสรุป
โดยปกติ คุณต้องแยกวิเคราะห์ XML ขนาดใหญ่เพื่อป้อนข้อมูลลงในฐานข้อมูล และสำหรับการประมวลผลข้อมูลที่เหมาะสม คุณต้องรู้ว่าข้อมูลนั้นเป็นของแท็กที่เปิดอยู่ ระดับของการซ้อนแท็ก และแท็กใดที่เปิดอยู่ในลำดับชั้นด้านบน ด้วยข้อมูลนี้ คุณสามารถประมวลผลไฟล์ได้อย่างถูกต้องโดยไม่มีปัญหาใดๆ
ในการทำเช่นนี้ คุณต้องแนะนำตัวแปรส่วนกลางหลายตัวที่จะรวบรวมข้อมูลเกี่ยวกับแท็กที่เปิด การซ้อน และข้อมูล
นี่คือตัวอย่างที่สามารถใช้ได้
ฟังก์ชัน webi_xml($file)
{
โกลบอล $webi_depth ; // ตัวนับเพื่อติดตามความลึกของรัง
$webi_depth = 0 ;
โกลบอล $webi_tag_open ; // จะมีอาร์เรย์ของแท็กที่เปิดอยู่ในปัจจุบัน
$webi_tag_open = array();
โกลบอล $webi_data_temp ; // อาร์เรย์นี้จะมีข้อมูลของหนึ่งแท็ก
####################################################
### ฟังก์ชั่นการจัดการข้อมูล
ข้อมูลฟังก์ชัน ($parser , $data )
{
โกลบอล $webi_depth ;
โกลบอล $webi_tag_open ;
โกลบอล $webi_data_temp ;
// เพิ่มข้อมูลลงในอาร์เรย์ด้วยการซ้อนและแท็กที่เปิดอยู่ในปัจจุบัน
$webi_data_temp [ $webi_depth ][ $webi_tag_open [ $webi_depth ]][ "data" ].= $data ;
}
############################################
####################################################
### ฟังก์ชั่นแท็กเปิด
ฟังก์ชัน startElement ($parser , $name , $attrs )
{
โกลบอล $webi_depth ;
โกลบอล $webi_tag_open ;
โกลบอล $webi_data_temp ;
// หากระดับการซ้อนไม่เป็นศูนย์ แสดงว่ามีหนึ่งแท็กเปิดอยู่แล้ว
// และข้อมูลจากมันอยู่ในอาร์เรย์แล้ว คุณสามารถประมวลผลได้
ถ้า ($webi_depth)
{
"
;
พิมพ์"
"
;
print_r($webi_tag_open); // อาร์เรย์ของแท็กที่เปิดอยู่
พิมพ์"
" ;
// หลังจากประมวลผลข้อมูลแล้ว ให้ลบออกเพื่อเพิ่มหน่วยความจำ
unset($GLOBALS [ "webi_data_temp" ][ $webi_depth ]);
}
// ตอนนี้การเปิดแท็กถัดไปได้เริ่มขึ้นแล้ว และการประมวลผลต่อไปจะเกิดขึ้นในขั้นตอนต่อไป
$webi_deep++; // เพิ่มการทำรัง
$webi_tag_open [ $webi_depth ]= $name ; // เพิ่มแท็กเปิดให้กับอาร์เรย์ข้อมูล
$webi_data_temp [ $webi_depth ][ $name ][ "attrs" ]= $attrs ; // ตอนนี้เพิ่มแอตทริบิวต์แท็ก
}
###############################################
#################################################
## ฟังก์ชั่นปิดแท็ก
ฟังก์ชั่น endElement ($parser , $name ) (
โกลบอล $webi_depth ;
โกลบอล $webi_tag_open ;
โกลบอล $webi_data_temp ;
// การประมวลผลข้อมูลเริ่มต้นที่นี่ เช่น การเพิ่มลงในฐานข้อมูล การบันทึกลงในไฟล์ เป็นต้น
// $webi_tag_open มีห่วงโซ่ของแท็กเปิดโดยระดับการซ้อน
// ตัวอย่างเช่น $webi_tag_open[$webi_depth] มีชื่อของแท็กเปิดที่กำลังประมวลผลข้อมูลอยู่
// ระดับการซ้อนแท็ก $webi_depth
// $webi_data_temp[$webi_depth][$webi_tag_open[$webi_depth]]["attrs"] อาร์เรย์ของแอตทริบิวต์แท็ก
// $webi_data_temp[$webi_depth][$webi_tag_open[$webi_depth]]["data"] ข้อมูลแท็ก
พิมพ์ "ข้อมูล" $webi_tag_open [ $webi_depth ] "--" .($webi_data_temp [ $webi_depth ][ $webi_tag_open [ $webi_depth ]][ "data" ]) "
"
;
print_r ($webi_data_temp [ $webi_depth ][ $webi_tag_open [ $webi_depth ]][ "attrs" ]);
พิมพ์"
"
;
print_r($webi_tag_open);
พิมพ์"
" ;
Unset($GLOBALS [ "webi_data_temp" ]); // หลังจากประมวลผลข้อมูลแล้ว ให้ลบอาร์เรย์ที่มีข้อมูลทั้งหมด เนื่องจากแท็กถูกปิด
unset($GLOBALS [ "webi_tag_open" ][ $webi_depth ]); // ลบข้อมูลเกี่ยวกับแท็กที่เปิดนี้... เนื่องจากปิดแล้ว
$webi_depth --; // ลดการทำรัง
}
############################################
$xml_parser = xml_parser_create();
xml_parser_set_option ($xml_parser , XML_OPTION_CASE_FOLDING , จริง );
// ระบุฟังก์ชันที่จะทำงานเมื่อเปิดและปิดแท็ก
xml_set_element_handler($xml_parser , "startElement" , "endElement" );
// ระบุฟังก์ชันสำหรับการทำงานกับ data
xml_set_character_data_handler($xml_parser , "ข้อมูล" );
// เปิดไฟล์
$fp = fopen($file , "r" );
$perviy_vxod = 1 ; // แฟล็กสำหรับตรวจสอบอินพุตแรกไปยังไฟล์
$data = "" ; // ที่นี่เรารวบรวมบางส่วนของข้อมูลจากไฟล์และส่งไปยัง parser xml
// วนซ้ำจนถึงจุดสิ้นสุดของไฟล์ที่พบ
ในขณะที่ (! feof ($fp ) และ $fp )
{
$simvol = fgetc($fp); // อ่านอักขระหนึ่งตัวจากไฟล์
$data .= $simvol ; // เพิ่มอักขระนี้ในข้อมูลที่จะส่ง
// หากอักขระไม่ใช่แท็กปิดท้าย ให้กลับไปที่จุดเริ่มต้นของลูปและเพิ่มอักขระอีกหนึ่งตัวในข้อมูล เป็นต้น จนกว่าจะพบแท็กสิ้นสุด
if($simvol != ">" ) ( ทำต่อ;)
// หากพบแท็กปิด ให้ส่งข้อมูลที่รวบรวมนี้ไปยังการประมวลผล
// ตรวจสอบว่าเป็นรายการแรกในไฟล์หรือไม่ จากนั้นให้ลบทุกอย่างที่อยู่หน้าแท็ก
// เนื่องจากบางครั้งอาจมีขยะก่อนที่จะเริ่ม XML (ตัวแก้ไขเงอะงะหรือสคริปต์ได้รับไฟล์จากเซิร์ฟเวอร์อื่น)
if($perviy_vxod ) ( $data = strstr ($data , ""
);
$perviy_vxod
=
0
;}
// ตอนนี้เราส่งข้อมูลไปยัง parser 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 );
หยุดพัก;
}
// หลังจากแยกวิเคราะห์ เราจะทิ้งข้อมูลที่รวบรวมไว้สำหรับขั้นตอนต่อไปของลูป
$data = "" ;
}
fclose($fp);
xml_parser_free($xml_parser );
// ลบตัวแปรโกลบอล
unset($GLOBALS [ "webi_depth" ]);
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 max_execution_time 6000
ตัวอย่างเหล่านี้จะเพิ่มเวลาทำงานของสคริปต์เป็น 6000 วินาที
คุณสามารถเพิ่มเวลาด้วยวิธีนี้ได้เฉพาะในเซฟโหมดปิด
หากคุณมีสิทธิ์เข้าถึงเพื่อแก้ไข php.ini คุณสามารถเพิ่มเวลาด้วย
max_execution_time = 6000
ตัวอย่างเช่น บนมาสเตอร์โฮสต์โฮสติ้ง ในขณะที่เขียนนี้ การเพิ่มเวลาสคริปต์เป็นสิ่งต้องห้าม แม้จะปิดใช้งานเซฟโหมด แต่หากคุณเป็นมือโปร คุณสามารถสร้าง php ของคุณบนมาสเตอร์โฮสต์ได้ แต่นี่ไม่ใช่ในบทความนี้ .
ตัวอย่างบางส่วนในคู่มือนี้รวมถึงสตริง XML แทนที่จะทำซ้ำในทุกตัวอย่าง ให้ใส่บรรทัดนี้ในไฟล์และรวมไว้ในทุกตัวอย่าง บรรทัดนี้แสดงในตัวอย่างต่อไปนี้ นอกจากนี้ คุณสามารถสร้างเอกสาร XML และอ่านด้วยฟังก์ชัน simplexml_load_file().
ตัวอย่าง #1 ไฟล์ Example.php พร้อมสตริง XML
$xmlstr =<<
มันเป็นภาษาสคริปต์หรือไม่? เปิดเผยหมดแล้วในสารคดีเรื่องนี้
คล้ายกับหนังสยองขวัญ
XML
?>
SimpleXML ใช้งานง่ายมาก! ลองรับสตริงหรือตัวเลขจากเอกสาร XML ที่เกี่ยวข้อง
ตัวอย่าง #2 รับส่วนหนึ่งของเอกสาร
รวม "example.php" ;
echo $movies -> ภาพยนตร์ [ 0 ] -> พล็อต ;
?>
ดังนั้นจึงเป็นภาษา ยังคงเป็นภาษาโปรแกรม หรือเป็นภาษาสคริปต์? ทุกอย่างถูกเปิดเผยในสารคดีที่ดูเหมือนหนังสยองขวัญเรื่องนี้
ใน PHP คุณสามารถเข้าถึงองค์ประกอบในเอกสาร XML ที่มีอักขระที่ไม่ถูกต้อง (เช่น ยัติภังค์) ในชื่อได้โดยการใส่ชื่อองค์ประกอบที่ระบุในวงเล็บปีกกาและเครื่องหมายอะพอสทรอฟี
ตัวอย่าง #3 รับสตริง
รวม "example.php" ;
echo $movies -> movie ->( "great-lines" )-> line ;
?>
ผลลัพธ์ของการรันตัวอย่างนี้:
PHP แก้ปัญหาทั้งหมดของฉันบนเว็บ
ตัวอย่าง #4 การเข้าถึงองค์ประกอบที่ไม่ซ้ำใน SimpleXML
ในกรณีที่มีองค์ประกอบย่อยหลายอินสแตนซ์ในองค์ประกอบหลักเดียวกัน จะต้องใช้วิธีวนซ้ำมาตรฐาน
รวม "example.php" ;
$movies = ใหม่ SimpleXMLElement($xmlstr );
/* สำหรับแต่ละโหนด
foreach ($movies -> movie -> character -> character เป็น $character ) (
echo $character -> name , "เล่น" , $character -> นักแสดง , PHP_EOL ;
}
?>
ผลลัพธ์ของการรันตัวอย่างนี้:
นางสาว. Coder รับบทเป็น Onlivia Actora Mr. Coder เล่น El ActÓr
ความคิดเห็น:
คุณสมบัติ ( $movies->moviesในตัวอย่างก่อนหน้านี้) ไม่ใช่อาร์เรย์ เป็นวัตถุ iterable ในรูปแบบของอาร์เรย์
ตัวอย่าง #5 การใช้แอตทริบิวต์
จนถึงตอนนี้ เราได้รับเพียงชื่อและค่าขององค์ประกอบเท่านั้น SimpleXML ยังสามารถเข้าถึงแอตทริบิวต์ขององค์ประกอบ แอตทริบิวต์องค์ประกอบสามารถเข้าถึงได้ในลักษณะเดียวกับองค์ประกอบอาร์เรย์ ( อาร์เรย์).
รวม "example.php" ;
$movies = ใหม่ SimpleXMLElement($xmlstr );
/* เข้าถึงโหนด
* เราจะแสดงมาตราส่วนการให้คะแนนด้วย */
foreach ($movies -> หนัง [ 0 ]-> ให้คะแนนเป็น $rating ) (
สวิตช์ ((สตริง) คะแนน $ [ "ประเภท" ]) ( // รับแอตทริบิวต์องค์ประกอบโดย index
กรณี "นิ้วโป้ง" :
echo $rating , " ยกนิ้วให้ " ;
หยุดพัก;
กรณี "ดาว" :
echo $rating , "ดาว" ;
หยุดพัก;
}
}
?>
ผลลัพธ์ของการรันตัวอย่างนี้:
7 ยกนิ้วให้5ดาว
ตัวอย่าง #6 การเปรียบเทียบองค์ประกอบและคุณลักษณะกับข้อความ
หากต้องการเปรียบเทียบองค์ประกอบหรือแอตทริบิวต์กับสตริง หรือส่งผ่านไปยังฟังก์ชันเป็นข้อความ คุณต้องแปลงเป็นสตริงโดยใช้ (สตริง). มิฉะนั้น PHP จะถือว่าองค์ประกอบนั้นเป็นวัตถุ
รวม "example.php" ;
$movies = ใหม่ SimpleXMLElement($xmlstr );
ถ้า ((สตริง) $movies -> movie -> title == "PHP: Parser ปรากฏขึ้น") {
พิมพ์ "ภาพยนตร์เรื่องโปรดของฉัน";
}
echo htmlentities ((สตริง) $movies -> movie -> title );
?>
ผลลัพธ์ของการรันตัวอย่างนี้:
หนังโปรดของฉัน PHP: The Parser Appears
ตัวอย่าง #7 การเปรียบเทียบสององค์ประกอบ
SimpleXMLElements สองรายการถือว่าแตกต่างกัน แม้ว่าจะชี้ไปที่อ็อบเจ็กต์เดียวกันกับ PHP 5.2.0
รวม "example.php" ;
$movies1 = ใหม่ SimpleXMLElement($xmlstr );
$movies2 = ใหม่ SimpleXMLElement($xmlstr );
var_dump ($movies1 == $movies2 ); // เท็จตั้งแต่ PHP 5.2.0
?>
ผลลัพธ์ของการรันตัวอย่างนี้:
Beispiel #8 ใช้ XPath
SimpleXML รวมการสนับสนุน XPath ดั้งเดิม ค้นหารายการทั้งหมด
รวม "example.php" ;
$movies = ใหม่ SimpleXMLElement($xmlstr );
foreach ($movies -> xpath("//character" ) เป็น $character ) (
echo $character -> name , "เล่น" , $character -> นักแสดง , PHP_EOL ;
}
?>
"// " ทำหน้าที่เป็นไวด์การ์ด หากต้องการระบุพาธแบบสัมบูรณ์ ให้ข้ามเครื่องหมายสแลชตัวใดตัวหนึ่ง
ผลลัพธ์ของการรันตัวอย่างนี้:
นางสาว. Coder รับบทเป็น Onlivia Actora Mr. Coder เล่นโดย El ActÓr
ตัวอย่าง #9 การตั้งค่าค่า
ข้อมูลใน SimpleXML ไม่จำเป็นต้องเปลี่ยนแปลงได้ วัตถุช่วยให้คุณสามารถจัดการองค์ประกอบทั้งหมดได้
รวม "example.php" ;
$movies = ใหม่ SimpleXMLElement($xmlstr );
$movies -> ภาพยนตร์ [ 0 ]-> อักขระ -> อักขระ [ 0 ]-> name = "Miss Coder" ;
เสียงสะท้อน $movies -> asXML();
?>
ผลลัพธ์ของการรันตัวอย่างนี้:
ตัวอย่าง #10 การเพิ่มองค์ประกอบและคุณลักษณะ
ใน PHP 5.1.3, SimpleXML มีความสามารถในการเพิ่มองค์ประกอบลูกและแอตทริบิวต์ได้อย่างง่ายดาย
รวม "example.php" ;
$movies = ใหม่ SimpleXMLElement($xmlstr );
$character = $movies -> ภาพยนตร์ [ 0 ]-> ตัวอักษร -> addChild("character" );
$character -> addChild("name" , "Mr. Parser" );
$character -> addChild("นักแสดง" , "John Doe" );
$rating = $movies -> หนัง [ 0 ] -> addChild("เรตติ้ง" , "PG" );
คะแนน $ -> addAttribute ("ประเภท" , "mpaa" );
เสียงสะท้อน $movies -> asXML();
?>
ผลลัพธ์ของการรันตัวอย่างนี้:
Beispiel #11 โต้ตอบกับDOM
PHP สามารถแปลงโหนด XML จาก SimpleXML เป็นรูปแบบ DOM และในทางกลับกัน ตัวอย่างนี้แสดงวิธีการแก้ไของค์ประกอบ DOM ใน SimpleXML
$dom = DOMDocument ใหม่ ;
$dom -> loadXML( "
ถ้า (! $dom ) (
เสียงก้อง "เกิดข้อผิดพลาดในการแยกวิเคราะห์เอกสาร";
ทางออก;
}
$books = simplexml_import_dom($dom );
echo $books -> book [ 0 ]-> title ;
?>
ผลลัพธ์ของการรันตัวอย่างนี้:
4 ปีที่แล้ว
มี "เคล็ดลับ" ทั่วไปที่มักเสนอให้แปลงวัตถุ SimpleXML เป็นอาร์เรย์ โดยเรียกใช้ผ่าน json_encode() และ json_decode() ฉันต้องการอธิบายว่าเหตุใดจึงเป็นความคิดที่ไม่ดี
อย่างง่ายที่สุด เนื่องจากจุดรวมของ SimpleXML คือใช้งานง่ายกว่าและมีประสิทธิภาพมากกว่าอาร์เรย์ธรรมดา ตัวอย่างเช่น คุณสามารถเขียนbar -> baz [ "bing" ] ?> และมีความหมายเดียวกับbar [ 0 ]-> baz [ 0 ][ "bing" ] ?> ไม่ว่าจะมีองค์ประกอบ bar หรือ baz กี่ตัวใน XML และถ้าคุณเขียนbar [ 0 ]-> baz [ 0 ] ?> คุณได้รับเนื้อหาสตริงทั้งหมดของโหนดนั้น - รวมถึงส่วน CDATA - ไม่ว่าจะมีองค์ประกอบย่อยหรือแอตทริบิวต์หรือไม่ คุณยังมีสิทธิ์เข้าถึงข้อมูลเนมสเปซ ความสามารถในการแก้ไข XML อย่างง่าย และแม้กระทั่งความสามารถในการ "นำเข้า" ลงในวัตถุ DOM เพื่อการจัดการที่มีประสิทธิภาพยิ่งขึ้น ทั้งหมดนี้หายไปโดยการเปลี่ยนวัตถุให้เป็นอาร์เรย์แทนที่จะอ่านเพื่อทำความเข้าใจตัวอย่างในหน้านี้
นอกจากนี้ เนื่องจากไม่ได้ออกแบบมาเพื่อจุดประสงค์นี้ การแปลงเป็น JSON และย้อนกลับจะสูญเสียข้อมูลจริงในบางสถานการณ์ ตัวอย่างเช่น องค์ประกอบหรือแอตทริบิวต์ใดๆ ในเนมสเปซจะถูกละทิ้ง และเนื้อหาข้อความใดๆ จะถูกละทิ้งหากองค์ประกอบมีลูกหรือแอตทริบิวต์ด้วย บางครั้งสิ่งนี้ไม่สำคัญ แต่ถ้าคุณคุ้นเคยกับการแปลงทุกอย่างเป็นอาร์เรย์ มันจะต่อยคุณในที่สุด
แน่นอน คุณสามารถเขียนการแปลงที่ชาญฉลาดกว่า ซึ่งไม่มีข้อจำกัดเหล่านี้ แต่ ณ จุดนั้น คุณจะไม่ได้รับค่าจาก SimpleXML เลย และควรใช้ฟังก์ชัน XML Parser ระดับล่าง หรือคลาส XMLReader เพื่อสร้างโครงสร้างของคุณ คุณจะยังไม่มีฟังก์ชันอำนวยความสะดวกพิเศษของ SimpleXML แต่นั่นคือการสูญเสียของคุณ
2 ปีที่แล้ว
หากสตริง xml ของคุณมีบูลีนที่เข้ารหัสด้วย "0" และ "1" คุณจะประสบปัญหาเมื่อคุณส่งองค์ประกอบไปยังบูลโดยตรง:
$xmlstr =<<
XML
$values = ใหม่ SimpleXMLElement($xmlstr);
$truevalue = (บูล)$values->truevalue; // จริง
$falsevalue = (บูล)$values->falsevalue; //จริงด้วย!!!
แทนที่จะต้อง cast to string หรือ int ก่อน:
$truevalue = (บูล)(int)$values->truevalue; // จริง
$falsevalue = (บูล)(int)$values->falsevalue; // เท็จ
9 ปีที่แล้ว
หากคุณต้องการเอาต์พุต xml ที่ถูกต้องในการตอบกลับ อย่าลืมตั้งค่าประเภทเนื้อหาส่วนหัวเป็น xml นอกเหนือจากการสะท้อนผลลัพธ์ของ asXML():
$xml = simplexml_load_file("...");
...
... xml สิ่ง
...
// เอาต์พุต xml ในการตอบกลับของคุณ:
ส่วนหัว ("ประเภทเนื้อหา: ข้อความ/xml");
เสียงสะท้อน $xml -> asXML();
?>
9 ปีที่แล้ว
จากไฟล์ README:
SimpleXML เป็นวิธีที่ง่ายในการเข้าถึงข้อมูล XML
ออบเจ็กต์ SimpleXML เป็นไปตามกฎพื้นฐานสี่ข้อ:
1) คุณสมบัติแสดงถึงองค์ประกอบ iterators
2) ดัชนีตัวเลขแสดงถึงองค์ประกอบ
3) ดัชนีที่ไม่ใช่ตัวเลขแสดงถึงคุณลักษณะ
4) การแปลงสตริงช่วยให้เข้าถึงข้อมูล TEXT ได้
เมื่อวนซ้ำคุณสมบัติ ส่วนขยายจะวนซ้ำเสมอ
โหนดทั้งหมดที่มีชื่อองค์ประกอบนั้น ดังนั้นเมธอด children() ต้องเป็น
เรียกเพื่อวนซ้ำโหนดย่อย แต่ยังทำสิ่งต่อไปนี้:
foreach ($obj->node_name เป็น $elem) (
// ทำอะไรบางอย่างกับ $elem
}
ส่งผลให้เกิดการวนซ้ำขององค์ประกอบ "node_name" อีกต่อไปแล้ว
จำเป็นต้องตรวจสอบเพื่อแยกแยะจำนวนโหนดประเภทนั้น
เมื่อมีการเข้าถึงข้อมูล TEXT องค์ประกอบผ่านคุณสมบัติ
ผลลัพธ์จะไม่รวมข้อมูล TEXT ขององค์ประกอบย่อย
ปัญหาที่ทราบ
============
เนื่องจากปัญหาเครื่องยนต์จึงไม่สามารถเข้าถึงได้ในขณะนี้
องค์ประกอบย่อยโดยดัชนี 0: $object->property
8 ปีที่แล้ว
ใช้สิ่งต่าง ๆ เช่น: is_object($xml->module->admin) เพื่อตรวจสอบว่ามีโหนดที่เรียกว่า "admin" จริงหรือไม่ ดูเหมือนจะไม่ทำงานตามที่คาดไว้ เนื่องจาก simplexml จะส่งคืนอ็อบเจ็กต์เสมอ - ในกรณีนี้จะเป็นอันว่าง - แม้ว่าจะไม่มีโหนดใดอยู่
สำหรับฉันฟังก์ชั่น empty() แบบเก่าที่ดีดูเหมือนว่าจะทำงานได้ดีในกรณีเช่นนี้
8 ปีที่แล้ว
เคล็ดลับด่วนเกี่ยวกับคิวรี xpath และเนมสเปซเริ่มต้น ดูเหมือนว่าระบบ XML ที่อยู่เบื้องหลัง SimpleXML จะมีการทำงานเหมือนกับที่ฉันเชื่อว่าระบบ XML .NET ใช้: เมื่อเราต้องการระบุบางสิ่งในเนมสเปซเริ่มต้น เราจะต้องประกาศเนมสเปซโดยใช้ registerXPathNamespace แล้วใช้คำนำหน้าเพื่อ ระบุอย่างอื่นในองค์ประกอบชีวิตเนมสเปซเริ่มต้น
$string =<<
ฉันรู้ว่านั่นคือคำตอบ แต่คำถามคืออะไร
XML
$xml = simplexml_load_string ($สตริง );
$xml -> registerXPathNamespace("def" , "http://www.w3.org/2005/Atom");
$nodes = $xml -> xpath("//def:document/def:title" );
?>
9 ปีที่แล้ว
ในขณะที่ SimpleXMLElement อ้างว่า iterable ดูเหมือนจะไม่ได้ใช้ฟังก์ชันอินเทอร์เฟซ Iterator มาตรฐาน เช่น::next และ::reset อย่างถูกต้อง ดังนั้นในขณะที่ foreach() ทำงาน ฟังก์ชันเช่น next(), current() หรือ each() ดูเหมือนจะไม่ทำงานตามที่คุณคาดไว้ ดูเหมือนว่าตัวชี้จะไม่เคลื่อนที่หรือถูกรีเซ็ตต่อไป
6 ปีที่แล้ว
หากการเข้ารหัสของเอกสาร XML ไม่ใช่ UTF-8 การประกาศการเข้ารหัสต้องมาต่อจาก version="..." และก่อน standalone="..." นี่เป็นข้อกำหนดของมาตรฐาน XML
หากการเข้ารหัสเอกสาร XML แตกต่างจาก UTF-8 การประกาศการเข้ารหัสควรทำตามหลังเวอร์ชัน = "..." และก่อนเวอร์ชันสแตนด์อโลน = "..." ข้อกำหนดนี้เป็น XML มาตรฐาน
ตกลง
ข้อผิดพลาดร้ายแรง: Uncaught ข้อยกเว้น "ข้อยกเว้น" พร้อมข้อความ "สตริงไม่สามารถแยกวิเคราะห์เป็น XML" ใน...
XML ภาษามาร์กอัปที่ขยายได้คือชุดของกฎสำหรับการเข้ารหัสเอกสารในรูปแบบที่เครื่องอ่านได้ XML เป็นรูปแบบที่นิยมสำหรับการแลกเปลี่ยนข้อมูลบนอินเทอร์เน็ต ไซต์ที่อัปเดตเนื้อหาบ่อยครั้ง เช่น ไซต์ข่าวสารหรือบล็อก มักจะให้ฟีด XML เพื่อให้โปรแกรมภายนอกทราบถึงการเปลี่ยนแปลงของเนื้อหา การส่งและแยกวิเคราะห์ข้อมูล XML เป็นงานทั่วไปสำหรับแอปพลิเคชันที่มีการเชื่อมต่อเครือข่าย บทเรียนนี้อธิบายวิธีแยกวิเคราะห์เอกสาร XML และใช้ข้อมูล
การเลือก Parser
การวิเคราะห์ช่อง
ขั้นตอนแรกในการแยกวิเคราะห์ฟีดคือการตัดสินใจว่าเขตข้อมูลใดที่คุณสนใจ โปรแกรมแยกวิเคราะห์แยกฟิลด์ที่กำหนดและละเว้นทุกอย่างอื่น
นี่คือข้อมูลโค้ดช่องที่จะแยกวิเคราะห์ในแอปพลิเคชันตัวอย่าง แต่ละโพสต์บน StackOverflow.com จะปรากฏในฟีดเป็นแท็กรายการ ซึ่งมีแท็กที่ซ้อนกันหลายแท็ก:
ฉันมีแอปพลิเคชันที่ต้องใช้ไฟล์ข้อมูล...
แอปพลิเคชันตัวอย่างดึงข้อมูลจากแท็กรายการและชื่อแท็กย่อย ลิงก์ และสรุป
การสร้างอินสแตนซ์ของ Parser
ขั้นตอนต่อไปคือการสร้างอินสแตนซ์ parser และเริ่มกระบวนการแยกวิเคราะห์ ในตัวอย่างนี้ parser จะถูกเตรียมข้อมูลเบื้องต้นเพื่อไม่ให้จัดการเนมสเปซและยังใช้ InputStream ที่ให้มาเป็นอินพุต กระบวนการแยกวิเคราะห์เริ่มต้นด้วยการเรียกใช้ nextTag() และเรียกใช้เมธอด readFeed() ซึ่งจะดึงและประมวลผลข้อมูลที่แอปพลิเคชันสนใจ:
คลาสสาธารณะ StackOverflowXmlParser (// เราไม่ได้ใช้เนมสเปซส่วนตัวแบบคงที่สุดท้าย String ns = null รายการแยกวิเคราะห์สาธารณะ (InputStream ใน) พ่น XmlPullParserException, IOException ( ลอง ( XmlPullParser parser = Xml.newPullParser (); parser.setFeature (XmlPullSPull_ParserC) , เท็จ); parser.setInput(ใน, null); parser.nextTag(); ส่งคืน readFeed(parser); ) ในที่สุด ( in.close(); ) ) ... )
ลบช่อง
เมธอด readFeed() ทำงานจริงในการประมวลผลฟีด องค์ประกอบที่มีแท็ก "รายการ" เป็นจุดเริ่มต้นสำหรับการประมวลผลช่องสัญญาณแบบเรียกซ้ำ หากแท็กถัดไปไม่ใช่แท็กรายการ จะถูกข้ามไป หลังจากที่ประมวลผล "ฟีด" ทั้งหมดซ้ำแล้วซ้ำอีก readFeed() จะส่งกลับรายการที่มีรายการ (รวมถึงรายการข้อมูลที่ซ้อนกัน) ที่ดึงมาจากฟีด รายการนี้จะถูกส่งคืนโดย parser
รายการส่วนตัว readFeed(XmlPullParser parser) พ่น XmlPullParserException, IOException ( รายการรายการ = ใหม่ ArrayList (); parser.require(XmlPullParser.START_TAG, ns, "feed"); ในขณะที่ (parser.next() != XmlPullParser.END_TAG) ( ถ้า (parser.getEventType() != XmlPullParser.START_TAG) ( ทำต่อ; ) ชื่อสตริง = parser.getName(); // เริ่มต้นด้วยการค้นหาแท็กรายการ if (name.equals("entry")) ( entries.add( readEntry(parser)); ) อื่น ๆ (ข้าม (parser); ) ) ส่งคืนรายการ; )
การแยกวิเคราะห์ XML
ขั้นตอนในการแยกวิเคราะห์ฟีด XML มีดังนี้:
ตัวอย่างนี้แสดงให้เห็นว่า parser แยกวิเคราะห์รายการ ชื่อเรื่อง ลิงก์ และข้อมูลสรุปอย่างไร
รายการคลาสคงที่สาธารณะ (ชื่อสตริงสุดท้ายสาธารณะ ลิงก์สตริงสุดท้ายสาธารณะ สรุปสตริงสุดท้ายสาธารณะ รายการส่วนตัว (ชื่อสตริง สรุปสตริง ลิงก์สตริง) ( this.title = ชื่อ; this.summary = สรุป; this.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) ( ทำต่อ; ) ชื่อสตริง = 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 ส่งคืนสรุป ) // สำหรับชื่อแท็กและสรุป แยกค่าข้อความ สตริงส่วนตัว readText (XmlPullParser parser) พ่น IOException, XmlPullParserException ( String result = ""; if (parser.next() == XmlPullParser.TEXT) ( result = parser.getText(); parser.nextTag(); ) ส่งกลับผลลัพธ์; ) ... )
ข้ามรายการที่คุณไม่ต้องการ
ในหนึ่งในขั้นตอนการแยกวิเคราะห์ XML ที่อธิบายข้างต้น parser จะข้ามแท็กที่เราไม่สนใจ ด้านล่างนี้คือรหัส parser สำหรับวิธี skip():
การข้ามโมฆะส่วนตัว (ตัวแยกวิเคราะห์ XmlPullParser) พ่น XmlPullParserException, IOException ( if (parser.getEventType() != XmlPullParser.START_TAG) ( โยนใหม่ IllegalStateException(); ) int ความลึก = 1 ในขณะที่ (ความลึก != 0) ( สวิตช์ (parser. ถัดไป()) ( กรณี XmlPullParser.END_TAG: ความลึก--; ตัวแบ่ง; กรณี XmlPullParser.START_TAG: ความลึก++; ตัวแบ่ง; ) ) )
นี่คือวิธีการทำงาน:
- เมธอดจะส่งข้อยกเว้นหากเหตุการณ์ปัจจุบันไม่ใช่ START_TAG
- ใช้ START_TAG และเหตุการณ์ทั้งหมดไม่เกิน END_TAG
- เพื่อให้แน่ใจว่าแท็กหยุดที่ END_TAG ที่ถูกต้อง และไม่ใช่แท็กแรกที่พบหลังจาก START_TAG เดิม จะติดตามความลึกของการซ้อน
ดังนั้น หากองค์ประกอบปัจจุบันมีองค์ประกอบที่ซ้อนกัน ความลึกจะไม่เป็น 0 จนกว่า parser จะประมวลผลเหตุการณ์ทั้งหมดระหว่าง START_TAG ดั้งเดิมและ END_TAG ที่สอดคล้องกัน ตัวอย่างเช่น พิจารณาว่า parser ข้ามไปอย่างไร
- ในครั้งแรกที่ผ่านห่วง while แท็กถัดไปที่ parser พบหลังจาก
นี่คือ START_TAG สำหรับ - ในการส่งผ่านรอบที่สองผ่านลูป while แท็กถัดไปที่ parser พบคือ END_TAG
- ในครั้งที่สามผ่านห่วง while แท็กถัดไปที่ parser พบคือ START_TAG
. ค่าความลึกเพิ่มขึ้นเป็น 2 - ในครั้งที่สี่ผ่านห่วง while แท็กถัดไปที่ parser พบคือ END_TAG. ค่าความลึกจะลดลงเหลือ 1
- ในครั้งที่ห้าและครั้งสุดท้ายผ่านห่วง while แท็กถัดไปที่ parser พบคือ END_TAG. ค่าความลึกลดลงเป็น 0 แสดงว่า
ข้ามองค์ประกอบสำเร็จแล้ว
กำลังประมวลผลข้อมูล XML
แอปพลิเคชันตัวอย่างรับและแยกวิเคราะห์ฟีด XML ใน AsyncTask การประมวลผลเสร็จสิ้นนอกเธรด UI หลัก เมื่อประมวลผลเสร็จสิ้น แอปพลิเคชันจะอัปเดตอินเทอร์เฟซผู้ใช้ในกิจกรรมหลัก (NetworkActivity)
ในตัวอย่างด้านล่าง เมธอด loadPage() จะทำสิ่งต่อไปนี้:
- เริ่มต้นตัวแปรสตริงด้วยค่า URL ที่ชี้ไปที่ฟีด XML
- เรียกใช้ DownloadXmlTask().execute(url) ใหม่ หากการตั้งค่าของผู้ใช้และการเชื่อมต่อเครือข่ายอนุญาต สิ่งนี้จะสร้างวัตถุ DownloadXmlTask ใหม่ (คลาสย่อย AsyncTask) และดำเนินการเมธอด execute() ซึ่งจะดาวน์โหลดและแยกวิเคราะห์ฟีดและส่งคืนผลลัพธ์สตริงที่จะแสดงในส่วนต่อประสานผู้ใช้
- doInBackground() รันเมธอด loadXmlFromNetwork() มันส่งผ่าน URL ของช่องเป็นพารามิเตอร์ loadXmlFromNetwork() วิธีการรับและประมวลผลช่องทาง เมื่อเสร็จสิ้นการประมวลผล จะส่งสตริงผลลัพธ์กลับ
- onPostExecute() รับสตริงที่ส่งคืนและแสดงในอินเทอร์เฟซผู้ใช้
ด้านล่างนี้คือเมธอด loadXmlFromNetwork() ซึ่งเรียกจาก DownloadXmlTask มันทำสิ่งต่อไปนี้:
- สร้างอินสแตนซ์ของ StackOverflowXmlParser นอกจากนี้ยังสร้างตัวแปรสำหรับออบเจ็กต์ List Entry และ title , url และ Summary เพื่อเก็บค่าที่ดึงมาจากฟีด XML สำหรับฟิลด์เหล่านั้น
- เรียก downloadUrl() ซึ่งจะดาวน์โหลดฟีดและส่งคืนเป็น InputStream
- ใช้ StackOverflowXmlParser เพื่อแยกวิเคราะห์ InputStream StackOverflowXmlParser เติมข้อมูลรายการด้วยข้อมูลจากฟีด
- ประมวลผลรายการ List และรวมข้อมูลฟีดกับมาร์กอัป HTML
- ส่งกลับสตริง HTML ที่แสดงในอินเทอร์เฟซผู้ใช้ของกิจกรรมหลัก AsyncTask ในเมธอด onPostExecute()
" + getResources().getString(R.string.page_title) + "
"); htmlString.append(" " + getResources().getString(R.string.updated) + " " + formatter.format(rightNow.getTime()) + ""); ลอง ( stream = downloadUrl(urlString); items = stackOverflowXmlParser.parse(stream); // ตรวจสอบให้แน่ใจว่า InputStream ถูกปิดหลังจากที่แอปนั้น // ใช้งานเสร็จแล้ว ) ในที่สุด ( if (stream != null) ( stream.close(); ) ) // StackOverflowXmlParser ส่งคืนรายการ (เรียกว่า "รายการ") ของวัตถุรายการ // แต่ละวัตถุรายการแสดงถึงโพสต์เดียวในฟีด XML // ส่วนนี้ประมวลผลรายการรายการที่จะรวมแต่ละรายการ รายการด้วยมาร์กอัป HTML // แต่ละรายการจะแสดงใน UI เป็นลิงก์ที่สามารถเลือกรวม // สรุปข้อความ สำหรับ (รายการรายการ: รายการ) ( htmlString. ต่อท้าย ("" + รายการชื่อ + "
"); // หากผู้ใช้ตั้งค่ากำหนดเพื่อรวมข้อความสรุป // เพิ่มไปที่การแสดงผล if (pref) ( htmlString.append(entry.summary); ) ) return htmlString.toString(); ) // รับการแสดงสตริงของ URL ตั้งค่าการเชื่อมต่อและรับ // อินพุต stream.private InputStream downloadUrl(String urlString) พ่น IOException ( URL url = URL ใหม่ (urlString); HttpURLConnection conn = (HttpURLConnection) url.openConnection() ; conn.setReadTimeout(10000 /* มิลลิวินาที */); conn.setConnectTimeout (15000 /* มิลลิวินาที */); conn.setRequestMethod("GET"); conn.setDoInput(true); // เริ่มการสืบค้น conn.connect( ); ส่งคืน conn.getInputStream(); )