ฉันควรใช้ตัวแยกวิเคราะห์ XML ใดใน C ++ [ปิด]


344

ฉันมีเอกสาร XML ที่ฉันต้องแยกวิเคราะห์และ / หรือฉันต้องการสร้างเอกสาร XML และเขียนลงในข้อความ (ไฟล์หรือหน่วยความจำ) เนื่องจากไลบรารีมาตรฐาน C ++ ไม่มีไลบรารีสำหรับสิ่งนี้ฉันควรใช้อะไร

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


ฉันชอบ tiCpp code.google.com/p/ticppเอกสารไม่ดี (ยัง?) แต่ฉันรักห้องสมุดรหัสสะอาดดี

ฉันเขียนgithub.com/igagis/mikroxml
igagis

คำตอบ:


679

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

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นคำถามแรกคือสิ่งนี้คุณต้องการอะไร

ฉันต้องการมาตรฐาน XML แบบเต็ม

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

คำถามต่อไปคือ: API ของคุณจำเป็นต้องสอดคล้องกับ DOM หรือ SAX หรือไม่

ฉันต้องการ DOM ที่แน่นอนและ / หรือความสอดคล้องของ SAX

ตกลงดังนั้นคุณต้องใช้ API เป็น DOM และ / หรือ SAX จริงๆ ไม่เพียงแค่เป็นตัวแยกวิเคราะห์แบบพุช SAX หรือตัวแยกวิเคราะห์แบบ DOM เท่านั้น มันจะต้องเป็น DOM ที่เกิดขึ้นจริงหรือแซ็กโซโฟนที่เกิดขึ้นจริงในขอบเขตที่ C ++ ช่วยให้

คุณได้เลือก:

xerces

นั่นคือทางเลือกของคุณ มันค่อนข้างแยกวิเคราะห์ C ++ XML เท่านั้นที่มีเต็ม (หรือใกล้เคียงที่สุดเท่าที่อนุญาตให้ C + +) DOM และ SAX สอดคล้อง นอกจากนี้ยังมีการรองรับ XInclude สนับสนุน XML Schema และคุณสมบัติอื่น ๆ อีกมากมาย

มันไม่มีการพึ่งพาที่แท้จริง มันใช้สิทธิ์การใช้งาน Apache

ฉันไม่สนใจ DOM และ / หรือ SAX

คุณได้เลือก:

libxml2

LibXML2 เสนออินเทอร์เฟซแบบ C (ถ้ามันรบกวนคุณจริง ๆ ให้ไปใช้ Xerces) แม้ว่าอินเทอร์เฟซนั้นจะค่อนข้างใช้วัตถุและห่อหุ้มได้ง่าย มันมีคุณสมบัติมากมายเช่นการสนับสนุน XInclude (ด้วยการโทรกลับเพื่อให้คุณสามารถบอกได้ว่ามันรับไฟล์มาจากที่ใด) ตัวจดจำ XPath 1.0, RelaxNG และ Schematron รองรับ (แม้ว่าข้อความผิดพลาดจะออกมาเยอะ ) และ เป็นต้นไป

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

มันใช้สิทธิ์การใช้งาน MIT

ฉันไม่ต้องการการปฏิบัติตาม XML แบบเต็ม

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

แล้วคุณมีความสำคัญอย่างไร คำถามต่อไปคืออะไรสิ่งที่สำคัญที่สุดสำหรับคุณใน XML ของคุณคืออะไร

ประสิทธิภาพการแยกวิเคราะห์ XML สูงสุด

แอปพลิเคชันของคุณต้องใช้ XML และเปลี่ยนเป็นโครงสร้างข้อมูล C ++ เร็วเท่าที่การแปลงนี้อาจเกิดขึ้นได้

คุณได้เลือก:

RapidXML

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

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

นอกจากนี้ยังเป็นตัวแยกวิเคราะห์สไตล์ DOM ดังนั้นจึงจำเป็นต้องให้คุณอ่านข้อความทั้งหมดอย่างไรก็ตามสิ่งที่ไม่ได้ทำคือคัดลอกข้อความใด ๆ (ปกติ) วิธี RapidXML ได้รับมากที่สุดของความเร็วคือโดยหมายถึงสตริงในสถานที่ สิ่งนี้ต้องการการจัดการหน่วยความจำเพิ่มเติมในส่วนของคุณ (คุณต้องเก็บสตริงนั้นไว้ในขณะที่ RapidXML ดูอยู่)

DOM ของ RapidXML เป็นกระดูกเปลือย คุณสามารถรับค่าสตริงสำหรับสิ่งต่าง ๆ คุณสามารถค้นหาคุณสมบัติตามชื่อ เกี่ยวกับมัน. ไม่มีฟังก์ชั่นอำนวยความสะดวกในการเปลี่ยนแอททริบิวเป็นค่าอื่น ๆ (ตัวเลข, วันที่, ฯลฯ ) คุณเพิ่งได้รับสาย

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

มันใช้สิทธิ์การใช้งาน MIT เป็นไลบรารีแบบส่วนหัวเท่านั้นโดยไม่มีการขึ้นต่อกัน

ฉันสนใจเกี่ยวกับประสิทธิภาพ แต่ก็ไม่มาก

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

คุณได้เลือก:

PugiXML

ในอดีตสิ่งนี้ทำหน้าที่เป็นแรงบันดาลใจสำหรับ RapidXML แต่โครงการทั้งสองนั้นแยกจากกันโดย Pugi นำเสนอฟีเจอร์ที่มากขึ้นในขณะที่ RapidXML นั้นเน้นไปที่ความเร็ว

PugiXML เสนอการสนับสนุนการแปลง Unicode ดังนั้นหากคุณมีเอกสาร UTF-16 บางส่วนและต้องการอ่านเป็น UTF-8 Pugi จะให้บริการ มันยังมีการติดตั้ง XPath 1.0 หากคุณต้องการสิ่งนั้น

แต่ Pugi ก็ยังค่อนข้างเร็ว เช่น RapidXML ไม่มีการอ้างอิงและเผยแพร่ภายใต้สิทธิ์การใช้งานของ MIT

อ่านเอกสารขนาดใหญ่

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

คุณได้เลือก:

libxml2

API แบบ SAX ของ Xerces จะทำงานได้ในความสามารถนี้ แต่ LibXML2 อยู่ที่นี่เพราะทำงานได้ง่ายขึ้นเล็กน้อย API สไตล์ SAX เป็น push-API: มันเริ่มต้นในการแยกวิเคราะห์กระแสข้อมูลและเพียงดับกิจกรรมที่คุณต้องจับ คุณถูกบังคับให้จัดการบริบทของรัฐและอื่น ๆ รหัสที่อ่าน API แบบ SAX นั้นมีมากมายมากกว่าที่หวังไว้

xmlReaderวัตถุของ LibXML2 คือ pull-API คุณขอให้ไปที่โหนดหรือองค์ประกอบ XML ถัดไป คุณไม่ได้บอก สิ่งนี้ช่วยให้คุณสามารถเก็บบริบทตามที่เห็นสมควรเพื่อจัดการเอนทิตีต่าง ๆ ในลักษณะที่สามารถอ่านได้ในโค้ดมากกว่าการโทรกลับเป็นจำนวนมาก

ทางเลือก

ชาวต่างชาติ

ชาวต่างชาติเป็นตัวแยกวิเคราะห์ C ++ ที่รู้จักกันดีซึ่งใช้ pull-parser API มันเขียนโดย James Clark

สถานะปัจจุบันใช้งานได้ รุ่นล่าสุดคือ 2.2.9 ซึ่งเผยแพร่เมื่อ (2019-09-25)

LlamaXML

มันเป็นการใช้งาน API แบบ StAX มันเป็นตัวแยกวิเคราะห์ที่คล้ายกับxmlReaderตัวแยกวิเคราะห์ของ LibXML2

แต่มันยังไม่ได้รับการปรับปรุงตั้งแต่ปี 2005 อีกครั้ง Caveat Emptor

สนับสนุน XPath

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

มีสามตัวเลือกอย่างมีประสิทธิภาพที่นี่:

  • LibXML2 : รองรับ XPath 1.0 อย่างเต็มรูปแบบ อีกครั้งเป็น C API ดังนั้นหากรบกวนคุณก็มีทางเลือกอื่น
  • PugiXML : มันมาพร้อมกับรองรับ XPath 1.0 เช่นกัน ดังที่กล่าวไว้ข้างต้นเป็น C ++ API มากกว่า LibXML2 ดังนั้นคุณอาจรู้สึกสบายใจ
  • TinyXML : มันไม่ได้มาพร้อมกับการสนับสนุน XPath แต่มีไลบรารีTinyXPathที่ให้บริการ TinyXML อยู่ระหว่างการแปลงเป็นเวอร์ชั่น 2.0 ซึ่งเปลี่ยนแปลง API ได้อย่างมากดังนั้น TinyXPath อาจไม่ทำงานกับ API ใหม่ เช่นเดียวกับ TinyXML เอง TinyXPath นั้นเผยแพร่ภายใต้ลิขสิทธิ์ zLib

เพิ่งได้งานทำ

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

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

คุณได้เลือก:

tinyxml

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

การเขียน XML ไม่มีปัญหาใน TinyXML คุณเพิ่งnewวางวัตถุบางอย่างแนบมันเข้าด้วยกันส่งเอกสารไปที่ a std::ostreamและทุกคนก็มีความสุข

นอกจากนี้ยังมีระบบนิเวศที่สร้างขึ้นรอบ ๆ TinyXML พร้อมด้วย API ที่เป็นมิตรกับ iterator มากกว่าและแม้แต่การติดตั้ง XPath 1.0 ที่ติดตั้งไว้ด้านบน

TinyXML ใช้สิทธิ์การใช้งาน zLib ซึ่งมากหรือน้อยกับ MIT License ที่มีชื่อแตกต่างกัน


6
ดูเหมือนเป็นสำเนาคัดลอก คุณสามารถลิงค์เอกสารต้นฉบับได้หรือไม่
Joel

28
@Joel: บ่อยครั้งเมื่อมีคนตอบคำถามของตัวเองด้วยการโพสต์ที่ดีมานานก็เป็นเพราะพวกเขาทำตามคำแนะนำของ Jeffโดยเฉพาะอย่างยิ่งเพราะสิ่งที่ดูเหมือนคำถามพอดูสามารถปิดก่อนที่คำตอบที่ดีสามารถ จะโพสต์ถ้าคนเขียนคำตอบที่ถูกต้องแล้วและมี โดยใช้เวลาสักครู่ในการเตรียมคำตอบก่อนที่เขาจะถามคำถาม :) Nicol ให้คำตอบที่ดีแก่เราทุกคนเกี่ยวกับคำถามที่ซ้ำซ้อนในอนาคต
sarnold

28
@Joel: ฉันกลัวว่าฉันไม่สามารถ มันเป็นเพียงเอกสารชั่วคราวที่ฉันคัดลอกมาจากใน Notepad ++ ฉันไม่เคยบันทึกดังนั้นฉันจึงไม่สามารถเชื่อมโยงคุณกับมันได้)
Nicol Bolas

6
อาจจะคุ้มค่าที่จะกล่าวถึง TinyXML เวอร์ชั่นใหม่: TinyXML-2 ใช้ API ที่คล้ายกันกับ TinyXML-1 และกรณีทดสอบที่หลากหลาย แต่การนำ parser ไปใช้นั้นถูกเขียนขึ้นใหม่ทั้งหมดเพื่อให้เหมาะสมกับการใช้งานในเกมมากขึ้น มันใช้หน่วยความจำน้อยกว่าเร็วกว่าและใช้การจัดสรรหน่วยความจำน้อยมาก
johnbakers

6
ฉันชอบคำถามและคำตอบนี้ แต่พบว่ามันมีอคติมากเกินไป ไม่ต้องพูดถึง MSXML และ XmlLite? หากการพกพาแบบหลาย paltform เป็นเหตุผลของคุณในการยกเว้นสิ่งเหล่านี้ควรมีการกล่าวถึงอย่างชัดเจนในคำถามและคำตอบ (ไม่เช่นนั้นบางคนอาจเลือกใช้เช่น Libxml2 สำหรับโครงการที่ใช้ Windows เท่านั้นซึ่งขอให้ปวดหัวที่สามารถหลีกเลี่ยงได้ง่าย)
Scrontch

17

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

การผูกข้อมูล XML ช่วยให้คุณสามารถใช้ XML โดยไม่ทำการแยกวิเคราะห์ XML หรือการทำให้เป็นอนุกรม คอมไพเลอร์การเชื่อมโยงข้อมูลจะสร้างรหัสระดับต่ำทั้งหมดโดยอัตโนมัติและนำเสนอข้อมูลที่แยกวิเคราะห์เป็นคลาส C ++ ที่สอดคล้องกับโดเมนแอปพลิเคชันของคุณ จากนั้นคุณทำงานกับข้อมูลนี้โดยการเรียกใช้ฟังก์ชันและทำงานกับชนิด C ++ (int, double, etc) แทนที่จะเปรียบเทียบสตริงและวิเคราะห์ข้อความ (ซึ่งเป็นสิ่งที่คุณทำกับ API การเข้าถึง XML ระดับต่ำเช่น DOM หรือ SAX)

ดูตัวอย่างเช่นข้อมูลโอเพนซอร์ส XML ที่มีผลผูกพันการดำเนินการที่ผมเขียน CodeSynthesis XSDและสำหรับน้ำหนักเบารุ่นพึ่งพาฟรีCodeSynthesis XSD / E


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

@ Nicol ฉันแก้ไขมันเป็นคำตอบ
JBentley

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

1

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


0

ใส่ของฉันเช่นกัน

http://www.codeproject.com/Articles/998388/XMLplusplus-version-The-Cplusplus-update-of-my-XML

ไม่มีคุณสมบัติการตรวจสอบ XML แต่เร็ว


2
มันเร็วกว่าหรือใช้กันอย่างแพร่หลายมากกว่า RapidXML หรือไม่? หรือ PugiXML พื้นที่โดเมนสำหรับตัวแยกวิเคราะห์ C ++ แบบ "เร็วไม่เหมือน - XML" ได้รับการครอบคลุมอย่างดี
Nicol Bolas

0

โอเคถ้าอย่างนั้น. ฉันได้สร้างใหม่เนื่องจากไม่มีรายการใดที่ไม่ตรงกับความต้องการของฉัน

ประโยชน์ที่ได้รับ:

  1. Pull-parser Streaming API ในระดับต่ำ ( Java StAX เช่น )
  2. สนับสนุนข้อยกเว้นและโหมด RTTI
  3. ขีด จำกัด สำหรับการใช้หน่วยความจำรองรับไฟล์ขนาดใหญ่ (ทดสอบด้วยไฟล์ XMarkขนาด 100 mibความเร็วขึ้นอยู่กับฮาร์ดแวร์)
  4. รองรับ UNICODE และตรวจจับการเข้ารหัสแหล่งสัญญาณอัตโนมัติ
  5. API ระดับสูงสำหรับการอ่านโครงสร้าง / POCO
  6. API การเขียนโปรแกรม Meta สำหรับการเขียนและสร้าง XSD จากโครงสร้าง / POCO พร้อมการสนับสนุนโครงสร้าง xml (คุณลักษณะและแท็กการซ้อน) (การสร้าง XSD ต้องการ RTTI แต่สามารถใช้กับการดีบักเพื่อทำให้ครั้งเดียวเท่านั้น)
  7. C ++ 11 - GCC และ VC ++ 15+

ข้อเสีย:

  1. ยังไม่ได้ตรวจสอบความถูกต้องของ DTD และ XSD
  2. การรับ XML / XSD โดย HTTP / HTTPS อยู่ระหว่างดำเนินการยังไม่เสร็จสิ้น
  3. ห้องสมุดใหม่

โครงการบ้าน


1
คุณสามารถเพิ่มมาตรฐานได้หรือไม่
Vadim Peretokin

-1

ในด้านความปลอดภัยลูกโลก , Inc เราใช้rapidxml เราลองใช้ตัวอื่น ๆ ทั้งหมด แต่ rapidxml น่าจะเป็นตัวเลือกที่ดีที่สุดสำหรับเรา

นี่คือตัวอย่าง:

 rapidxml::xml_document<char> doc;
    doc.parse<0>(xmlData);
    rapidxml::xml_node<char>* root = doc.first_node();

    rapidxml::xml_node<char>* node_account = 0;
    if (GetNodeByElementName(root, "Account", &node_account) == true)
    {
        rapidxml::xml_node<char>* node_default = 0;
        if (GetNodeByElementName(node_account, "default", &node_default) == true)
        {
            swprintf(result, 100, L"%hs", node_default->value());
            free(xmlData);
            return true;
        }
    }
    free(xmlData);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.