วิธีจัดการกับ XML ใน C #


87

วิธีที่ดีที่สุดในการจัดการกับเอกสาร XML, XSD และอื่น ๆ ใน C # 2.0 คืออะไร?

จะใช้คลาสใดเป็นต้นแนวทางปฏิบัติที่ดีที่สุดในการแยกวิเคราะห์และการทำเอกสาร XML เป็นต้น

แก้ไข: ยินดีต้อนรับคำแนะนำ. Net 3.5


1
สำหรับผู้ที่พยายามหาวิธีแก้ปัญหาที่ใช้งานได้มากกว่านี้ให้ละเว้น เป็นไลบรารี. NET เก่า ใช้ XDocument แทนและคุณจะประหยัดเวลาในการควักดวงตาด้วยความหงุดหงิด
AER

คำตอบ:


180

วิธีการหลักในการอ่านและเขียนใน C # 2.0 ทำได้ผ่านXmlDocumentคลาสคุณสามารถโหลดการตั้งค่าส่วนใหญ่ลงใน XmlDocument ได้โดยตรงผ่าน XmlReader ที่ยอมรับ

กำลังโหลด XML โดยตรง

XmlDocument document = new XmlDocument();
document.LoadXml("<People><Person Name='Nick' /><Person Name='Joe' /></People>");

กำลังโหลด XML จากไฟล์

XmlDocument document = new XmlDocument();
document.Load(@"C:\Path\To\xmldoc.xml");
// Or using an XmlReader/XmlTextReader
XmlReader reader = XmlReader.Create(@"C:\Path\To\xmldoc.xml");
document.Load(reader);

ฉันพบว่าวิธีที่ง่ายที่สุด / เร็วที่สุดในการอ่านเอกสาร XML คือการใช้ XPath

การอ่านเอกสาร XML โดยใช้ XPath (โดยใช้ XmlDocument ซึ่งอนุญาตให้เราแก้ไข)

XmlDocument document = new XmlDocument();
document.LoadXml("<People><Person Name='Nick' /><Person Name='Joe' /></People>");

// Select a single node
XmlNode node = document.SelectSingleNode("/People/Person[@Name = 'Nick']");

// Select a list of nodes
XmlNodeList nodes = document.SelectNodes("/People/Person");

หากคุณต้องการทำงานกับเอกสาร XSD เพื่อตรวจสอบความถูกต้องของเอกสาร XML คุณสามารถใช้สิ่งนี้ได้

การตรวจสอบเอกสาร XML กับ XSD Schemas

XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidateType = ValidationType.Schema;
settings.Schemas.Add("", pathToXsd); // targetNamespace, pathToXsd

XmlReader reader = XmlReader.Create(pathToXml, settings);
XmlDocument document = new XmlDocument();

try {
    document.Load(reader);
} catch (XmlSchemaValidationException ex) { Trace.WriteLine(ex.Message); }

การตรวจสอบความถูกต้องของ XML กับ XSD ที่แต่ละโหนด (UPDATE 1)

XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidateType = ValidationType.Schema;
settings.Schemas.Add("", pathToXsd); // targetNamespace, pathToXsd
settings.ValidationEventHandler += new ValidationEventHandler(settings_ValidationEventHandler);

XmlReader reader = XmlReader.Create(pathToXml, settings);
while (reader.Read()) { }

private void settings_ValidationEventHandler(object sender, ValidationEventArgs args)
{
    // e.Message, e.Severity (warning, error), e.Error
    // or you can access the reader if you have access to it
    // reader.LineNumber, reader.LinePosition.. etc
}

การเขียนเอกสาร XML (ด้วยตนเอง)

XmlWriter writer = XmlWriter.Create(pathToOutput);
writer.WriteStartDocument();
writer.WriteStartElement("People");

writer.WriteStartElement("Person");
writer.WriteAttributeString("Name", "Nick");
writer.WriteEndElement();

writer.WriteStartElement("Person");
writer.WriteStartAttribute("Name");
writer.WriteValue("Nick");
writer.WriteEndAttribute();
writer.WriteEndElement();

writer.WriteEndElement();
writer.WriteEndDocument();

writer.Flush();

(อัพเดท 1)

ใน. NET 3.5 คุณใช้ XDocument เพื่อทำงานที่คล้ายกัน ความแตกต่างคือคุณมีข้อได้เปรียบในการดำเนินการ Queries Linq เพื่อเลือกข้อมูลที่คุณต้องการ ด้วยการเพิ่มตัวเริ่มต้นอ็อบเจ็กต์คุณสามารถสร้างคิวรีที่ส่งคืนอ็อบเจ็กต์ของนิยามของคุณเองในคิวรีด้วย

    XDocument doc = XDocument.Load(pathToXml);
    List<Person> people = (from xnode in doc.Element("People").Elements("Person")
                       select new Person
                       {
                           Name = xnode.Attribute("Name").Value
                       }).ToList();

(อัพเดท 2)

วิธีที่ดีใน. NET 3.5 คือการใช้ XDocument เพื่อสร้าง XML อยู่ด้านล่าง ทำให้โค้ดปรากฏในรูปแบบที่คล้ายกันกับเอาต์พุตที่ต้องการ

XDocument doc =
        new XDocument(
              new XDeclaration("1.0", Encoding.UTF8.HeaderName, String.Empty),
              new XComment("Xml Document"),
              new XElement("catalog",
                    new XElement("book", new XAttribute("id", "bk001"),
                          new XElement("title", "Book Title")
                    )
              )
        );

สร้าง

<!--Xml Document-->
<catalog>
  <book id="bk001">
    <title>Book Title</title>
  </book>
</catalog>

สิ่งอื่น ๆ ล้มเหลวคุณสามารถดูบทความ MSDN ที่มีตัวอย่างมากมายที่ฉันได้กล่าวถึงที่นี่และอื่น ๆ http://msdn.microsoft.com/en-us/library/aa468556.aspx


3
คุณอาจต้องการชี้ให้เห็นว่าคุณกำลังใช้ XDocument ในตัวอย่างสุดท้ายเนื่องจาก XDocument ค่อนข้างแตกต่างจาก XmlDocument
Aaron Powell

2
การแก้ไข; ไม่มี C # 3.5; คุณหมายถึง. NET 3.5 และ C # 3.0
Marc Gravell

โอ้และ "ตัวเริ่มต้นวัตถุ]" ทันที "จะทำงานเหมือนกันกับ C # 3.0 และ XmlDocument เป็นส่วนใหญ่ แต่ก็ยังเป็นคำตอบที่ดีแม้ว่า (+1)
Marc Gravell

อาจเป็นเรื่องที่ควรค่าแก่การกล่าวถึงว่าหากคุณกำลังโหลดเอกสารเพื่อค้นหาด้วย XPath (และไม่ต้องแก้ไข) การใช้ XPathDocument จะมีประสิทธิภาพมากกว่ามาก
Oliver Hallam

การตรวจสอบสคีมานี้ทำโหนดต่อโหนดหรือไม่ ถ้าไม่มีวิธีทำโหนดต่อโหนดหรือไม่?
Malik Daud Ahmad Khohar

30

ขึ้นอยู่กับขนาด สำหรับ xml ขนาดเล็กถึงขนาดกลาง DOM เช่นXmlDocument (เวอร์ชัน C # /. NET ใด ๆ ) หรือXDocument (.NET 3.5 / C # 3.0) เป็นผู้ชนะที่ชัดเจน สำหรับการใช้ xsd, คุณสามารถโหลด XML ใช้XmlReaderและ XmlReader ยอมรับ (เพื่อสร้าง ) ความXmlReaderSettings อ็อบเจ็กต์ XmlReaderSettings มีคุณสมบัติSchemasที่สามารถใช้เพื่อทำการตรวจสอบความถูกต้อง xsd (หรือ dtd)

สำหรับการเขียน xml จะใช้สิ่งเดียวกันโดยสังเกตว่าการจัดวางเนื้อหาด้วย LINQ-to-XML (XDocument) นั้นง่ายกว่า XmlDocument รุ่นเก่าเล็กน้อย

อย่างไรก็ตามสำหรับ xml ขนาดใหญ่ DOM อาจทำให้หน่วยความจำมากเกินไปซึ่งในกรณีนี้คุณอาจต้องใช้ XmlReader / XmlWriter โดยตรง

สุดท้ายสำหรับการจัดการ xml คุณอาจต้องการใช้XslCompiledTransform (เลเยอร์ xslt)

ทางเลือกในการทำงานกับ xml คือการทำงานกับโมเดลอ็อบเจ็กต์ คุณสามารถใช้xsd.exeเพื่อสร้างคลาสที่เป็นตัวแทนของโมเดลที่สอดคล้องกับ xsd และเพียงแค่โหลด xml เป็นอ็อบเจกต์จัดการกับ OO จากนั้นจัดลำดับอ็อบเจ็กต์เหล่านั้นอีกครั้ง คุณทำเช่นนี้กับXmlSerializer


เพื่อจัดการ (องค์ประกอบเพิ่ม / ผู้สนับสนุน) เอกสาร XML ขนาดใหญ่ (บรรทัด 40k) วิธีที่ดีที่สุดคืออะไร? ฉันเคยใช้ LINQ-to-XML
Neyoh

12

คำตอบของ nyxtom นั้นดีมาก ฉันจะเพิ่มสองสามอย่างเข้าไป:

หากคุณต้องการการเข้าถึงเอกสาร XML แบบอ่านอย่างเดียวXPathDocumentวัตถุที่มีน้ำหนักเบากว่าXmlDocumentไฟล์.

ข้อเสียของการใช้XPathDocumentคือการที่คุณไม่สามารถใช้คุ้นเคยSelectNodesและวิธีการของSelectSingleNode XmlNodeคุณต้องใช้เครื่องมือที่IXPathNavigableให้: ใช้CreateNavigatorเพื่อสร้างXPathNavigatorและใช้XPathNavigatorเพื่อสร้างXPathNodeIteratorเพื่อวนซ้ำรายการโหนดที่คุณพบผ่าน XPath โดยทั่วไปต้องใช้โค้ดมากกว่าXmlDocumentวิธีการสองสามบรรทัด

แต่: XmlDocumentและXmlNodeคลาสใช้งานIXPathNavigableดังนั้นโค้ดใด ๆ ที่คุณเขียนเพื่อใช้วิธีการเหล่านั้นบนXPathDocumentจะใช้ได้กับXmlDocumentไฟล์. หากคุณคุ้นเคยกับการเขียนต่อต้านIXPathNavigableวิธีการของคุณสามารถใช้กับวัตถุใดวัตถุหนึ่งได้ (นี่คือสาเหตุที่การใช้XmlNodeและXmlDocumentในวิธีการลายเซ็นถูกตั้งค่าสถานะโดย FxCop)

น่าเศร้า, XDocumentและXElement(และXNodeและXObject) IXPathNavigableไม่ได้ดำเนินการ

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

XmlReader นอกจากนี้ยังมีวิธีที่ง่ายที่สุดในการประมวลผลชิ้นส่วนเอกสาร XML เช่นสตรีมขององค์ประกอบ XML โดยไม่รวมองค์ประกอบที่อ็อพชัน FOR XML RAW ของ SQL Server ส่งกลับ

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


3
โปรดทราบว่ามีวิธีการขยายในการXPathNavigator CreateNavigator(this XNode node)สร้างXPathNavigatorจากXNode(ซึ่งรวมถึงคลาสที่ได้รับXDocument)
Dave

5

ก่อนอื่นทำความรู้จักคลาสXDocumentและXElementใหม่เนื่องจากเป็นการปรับปรุงจากตระกูล XmlDocument ก่อนหน้านี้

  1. พวกเขาทำงานร่วมกับ LINQ
  2. เร็วขึ้นและมีน้ำหนักเบามากขึ้น

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

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


ฉันยอมรับว่าพวกเขา (XDocument และอื่น ๆ ) ดีมาก แต่ OP ถามเกี่ยวกับ C # 2.0
Marc Gravell


2

หากคุณกำลังทำงานใน. NET 3.5 และคุณไม่ได้ติดใจรหัสทดลองคุณสามารถตรวจสอบ LINQ ถึง XSD ( http://blogs.msdn.com/xmlteam/archive/2008/02/21/linq-to- xsd-alpha-0-2.aspx ) ซึ่งจะสร้างคลาส. NET จาก XSD (รวมถึงกฎในตัวจาก XSD)

จากนั้นจะมีความสามารถในการเขียนลงไฟล์โดยตรงและอ่านจากไฟล์เพื่อให้แน่ใจว่าเป็นไปตามกฎ XSD

ฉันขอแนะนำให้มี XSD สำหรับเอกสาร XML ที่คุณทำงานด้วย:

  • อนุญาตให้คุณบังคับใช้กฎใน XML
  • อนุญาตให้ผู้อื่นเห็นว่า XML เป็น / จะมีโครงสร้างอย่างไร
  • สามารถใช้สำหรับการตรวจสอบความถูกต้องของ XML

ฉันพบว่า Liquid XML Studio เป็นเครื่องมือที่ยอดเยี่ยมในการสร้าง XSD และฟรี!


2

การเขียน XML ด้วยคลาส XmlDocument

//itemValues is collection of items in Key value pair format
//fileName i name of XML file which to creatd or modified with content
    private void WriteInXMLFile(System.Collections.Generic.Dictionary<string, object> itemValues, string fileName)
    {
        string filePath = "C:\\\\tempXML\\" + fileName + ".xml";
        try
        {

            if (System.IO.File.Exists(filePath))
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(filePath);                   

                XmlNode rootNode = doc.SelectSingleNode("Documents");

                XmlNode pageNode = doc.CreateElement("Document");
                rootNode.AppendChild(pageNode);


                foreach (string key in itemValues.Keys)
                {

                    XmlNode attrNode = doc.CreateElement(key);
                    attrNode.InnerText = Convert.ToString(itemValues[key]);
                    pageNode.AppendChild(attrNode);
                    //doc.DocumentElement.AppendChild(attrNode);

                }
                doc.DocumentElement.AppendChild(pageNode);
                doc.Save(filePath);
            }
            else
            {
                XmlDocument doc = new XmlDocument();
                using(System.IO.FileStream fs = System.IO.File.Create(filePath))
                {
                    //Do nothing
                }

                XmlNode rootNode = doc.CreateElement("Documents");
                doc.AppendChild(rootNode);
                doc.Save(filePath);

                doc.Load(filePath);

                XmlNode pageNode = doc.CreateElement("Document");
                rootNode.AppendChild(pageNode);

                foreach (string key in itemValues.Keys)
                {                          
                    XmlNode attrNode = doc.CreateElement(key);                           
                    attrNode.InnerText = Convert.ToString(itemValues[key]);
                    pageNode.AppendChild(attrNode);
                    //doc.DocumentElement.AppendChild(attrNode);

                }
                doc.DocumentElement.AppendChild(pageNode);

                doc.Save(filePath);

            }
        }
        catch (Exception ex)
        {

        }

    }

OutPut look like below
<Dcouments>
    <Document>
        <DocID>01<DocID>
        <PageName>121<PageName>
        <Author>Mr. ABC<Author>
    <Dcoument>
    <Document>
        <DocID>02<DocID>
        <PageName>122<PageName>
        <Author>Mr. PQR<Author>
    <Dcoument>
</Dcouments>

1

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


ฉันประสบความสำเร็จอย่างมากกับ DataSet's นอกจากนี้ยังเป็นมิตรกับฐานข้อมูล
User1

1

ความคิดเห็นส่วนตัวของฉันในฐานะโปรแกรมเมอร์ C # คือวิธีที่ดีที่สุดในการจัดการกับ XML ใน C # คือการมอบหมายส่วนนั้นของโค้ดให้กับโครงการ VB .NET ใน. NET 3.5 VB .NET มี XML Literals ซึ่งทำให้จัดการกับ XML ได้ง่ายขึ้นมาก ดูที่นี่ตัวอย่าง:

ภาพรวมของ LINQ เป็น XML ใน Visual Basic

(อย่าลืมตั้งค่าหน้าให้แสดงรหัส VB ​​ไม่ใช่รหัส C #)

ฉันจะเขียนส่วนที่เหลือของโครงการใน C # แต่จัดการ XML ในโครงการ VB ที่อ้างอิง


ไม่คุ้มค่าที่จะ swtich เป็น vb สำหรับลิเทอรัล XML เท่านั้น XML จัดการกับตัวอักษรเท่านั้น หากส่ง xml เป็นพารามิเตอร์การสนับสนุนลิเทอรัล XML จะไม่ให้ประโยชน์กับคุณมากนัก แต่ไวยากรณ์ดั้งเดิมของ vb.net จะทำลายประสบการณ์การเขียนโปรแกรมที่มีความสุขของ C #
Gqqnbig

0

nyxtom,

"doc" และ "xdoc" ในตัวอย่างที่ 1 ไม่ควรตรงกันหรือไม่

XDocument **doc** = XDocument.Load(pathToXml);
List<Person> people = (from xnode in **xdoc**.Element("People").Elements("Person")
                   select new Person
                   {
                       Name = xnode.Attribute("Name").Value
                   }).ToList();

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

ขอบคุณเดวิด ตกลงมันจะไม่อนุญาตให้ฉันแสดงความคิดเห็นในเวลานั้น ไม่แน่ใจว่าทำไม
mokumaxCraig

0

คำตอบของ Cookey นั้นดี ... แต่นี่คือคำแนะนำโดยละเอียดเกี่ยวกับวิธีการสร้างวัตถุที่พิมพ์อย่างรุนแรงจาก XSD (หรือ XML) และทำให้เป็นอนุกรม / deserialize ในโค้ดไม่กี่บรรทัด:

คำแนะนำ


"หน้าที่คุณกำลังค้นหาไม่มีอยู่" :(
Ian Grainger

0

หากคุณต้องการแปลงข้อมูลระหว่างXmlNode<=> XNode<=> XElement
(เช่นเพื่อใช้ LINQ) ส่วนขยายนี้อาจเป็นประโยชน์สำหรับคุณ:

public static class MyExtensions
{
    public static XNode GetXNode(this XmlNode node)
    {
        return GetXElement(node);
    }

    public static XElement GetXElement(this XmlNode node)
    {
        XDocument xDoc = new XDocument();
        using (XmlWriter xmlWriter = xDoc.CreateWriter())
            node.WriteTo(xmlWriter);
        return xDoc.Root;
    }

    public static XmlNode GetXmlNode(this XElement element)
    {
        using (XmlReader xmlReader = element.CreateReader())
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(xmlReader);
            return xmlDoc;
        }
    }

    public static XmlNode GetXmlNode(this XNode node)
    {
        return GetXmlNode(node);
    }
}

การใช้งาน:

XmlDocument MyXmlDocument = new XmlDocument();
MyXmlDocument.Load("MyXml.xml");
XElement MyXElement = MyXmlDocument.GetXElement(); // Convert XmlNode to XElement
List<XElement> List = MyXElement.Document
   .Descendants()
   .ToList(); // Now you can use LINQ
...
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.