C #에서 XML을 다루는 방법


85

C # 2.0에서 XML 문서, XSD 등을 처리하는 가장 좋은 방법은 무엇입니까?

사용할 클래스 등 XML 문서를 구문 분석하고 만드는 모범 사례는 무엇입니까?

편집 : .Net 3.5 제안도 환영합니다.


더 실행 가능한 솔루션을 찾으려는 사람들에게는 이것을 무시하십시오. 오래된 .NET 라이브러리입니다. 대신 XDocument를 사용하면 좌절감으로 눈을 떼지
AER

답변:


177

C # 2.0에서 읽고 쓰는 기본 방법은 XmlDocument 클래스를 통해 수행됩니다 . 허용되는 XmlReader를 통해 대부분의 설정을 XmlDocument에 직접로드 할 수 있습니다.

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를 사용하는 것입니다.

XPath를 사용하여 XML 문서 읽기 (편집 할 수있는 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");

XML 문서의 유효성을 검사하기 위해 XSD 문서로 작업해야하는 경우이를 사용할 수 있습니다.

XSD 스키마에 대해 XML 문서 유효성 검사

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); }

각 노드에서 XSD에 대해 XML 유효성 검사 (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를 사용하여 유사한 작업을 수행합니다. 그러나 차이점은 필요한 정확한 데이터를 선택하기 위해 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는 XmlDocument와 상당히 다르기 때문에 마지막 예제에서 XDocument를 사용하고 있음을 지적 할 수 있습니다.
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 Khokhar

30

크기에 따라 다릅니다. 중소 규모 xml의 경우 XmlDocument (모든 C # /. NET 버전) 또는 XDocument (.NET 3.5 / C # 3.0) 와 같은 DOM 이 확실한 승자입니다. XSD를 사용하기 위해, 당신은 XML이 사용하여로드 할 수 있습니다 XmlReader를을 하고 XmlReader를이 (을 수락 작성 AN) XmlReaderSettings를 . XmlReaderSettings 개체에는 xsd (또는 dtd) 유효성 검사를 수행하는 데 사용할 수 있는 Schemas 속성이 있습니다.

xml을 작성하는 경우에도 동일한 사항이 적용되며, 이전 XmlDocument보다 LINQ-to-XML (XDocument)을 사용하여 콘텐츠를 레이아웃하는 것이 조금 더 쉽습니다.

그러나 거대한 xml의 경우 DOM이 너무 많은 메모리를 꽉 채울 수 있으며,이 경우 XmlReader / XmlWriter를 직접 사용해야 할 수 있습니다.

마지막으로 xml을 조작하기 위해 XslCompiledTransform (xslt 레이어) 을 사용할 수 있습니다 .

xml 작업에 대한 대안은 개체 모델로 작업하는 것입니다. 당신이 사용할 수있는 xsd.exe를 XSD에 호환 모델을 대표하는 클래스를 생성하고, 단순히 XML로드 객체로를 , OO 그것을 조작하고, 다시 그 객체를 직렬화; XmlSerializer 로이 작업을 수행합니다 .


큰 XML 문서 (40k 라인)를 조작 (요소 추가 / 공급)합니다. 가장 좋은 방법은 무엇입니까? LINQ-to-XML을 사용했습니다.
Neyoh

12

nyxtom의 답변은 매우 좋습니다. 여기에 몇 가지를 추가하겠습니다.

XML 문서에 대한 읽기 전용 액세스가 필요한 경우 XPathDocumentXmlDocument.

사용의 단점은 .NET Framework의 XPathDocument익숙한 방법 SelectNodesSelectSingleNode방법을 사용할 수 없다는 것 입니다 XmlNode. 대신에서 IXPathNavigable제공 하는 도구를 사용해야 합니다. 사용 CreateNavigator하여를 만들고 XPathNavigator를 사용하여 XPathNavigator를 사용하여 XPathNodeIteratorXPath를 통해 찾은 노드 목록을 반복합니다. 일반적으로 XmlDocument메서드 보다 몇 줄 더 많은 코드가 필요 합니다.

그러나 XmlDocumentXmlNode클래스는을 구현 IXPathNavigable하므로에서 해당 메서드를 사용하기 위해 작성한 모든 코드 XPathDocumentXmlDocument. 에 대해 작성하는 데 익숙해지면 IXPathNavigable메서드가 두 객체에 대해 작동 할 수 있습니다. (이것이 FxCop에 의해 using XmlNodeand XmlDocumentin method signatures가 표시되는 이유 입니다.)

유감스럽게도, XDocument그리고 XElement(및 XNodeXObject) 구현하지 마십시오 IXPathNavigable.

nyxtom의 답변에없는 또 다른 것은 XmlReader. 일반적으로 XmlReaderXML 스트림을 처리를 시작하기 전에 객체 모델로 구문 분석하는 오버 헤드를 방지하기 위해 사용 합니다. 대신를 사용 XmlReader하여 입력 스트림을 한 번에 하나의 XML 노드로 처리합니다. 이것은 본질적으로 SAX에 대한 .NET의 대답입니다. 매우 큰 XML 문서를 처리하기위한 매우 빠른 코드를 작성할 수 있습니다.

XmlReader 또한 SQL Server의 FOR XML RAW 옵션이 반환하는 포함 요소가없는 XML 요소 스트림과 같이 XML 문서 조각을 처리하는 가장 간단한 방법을 제공합니다.

사용하는 코드 XmlReader는 일반적으로 읽고있는 XML 형식과 매우 밀접하게 연결됩니다. XPath를 사용하면 코드가 XML에 훨씬 더 느슨하게 결합 될 수 있으므로 일반적으로 올바른 대답입니다. 하지만을 사용해야 XmlReader할 때는 정말 필요합니다.


3
(파생 된 클래스를 포함 XPathNavigator CreateNavigator(this XNode node)하는) XPathNavigator에서 를 만드는 확장 메서드 가 있습니다 . XNodeXDocument
데이브

5

먼저 새로운 XDocumentXElement 클래스 에 대해 알아보십시오 . 이전 XmlDocument 제품군보다 개선 된 것입니다.

  1. LINQ와 함께 작동합니다.
  2. 더 빠르고 가볍습니다.

그러나 레거시 코드, 특히 이전에 생성 된 프록시로 작업하려면 이전 클래스를 계속 사용해야 할 수 있습니다. 이 경우 이러한 XML 처리 클래스 간의 상호 운용을위한 몇 가지 패턴에 익숙해 져야합니다.

나는 귀하의 질문이 매우 광범위하고 세부 사항을 제공하기 위해 단일 답변에 너무 많은 것이 필요하다고 생각하지만 이것이 제가 생각한 첫 번째 일반적인 대답이며 시작 역할을합니다.


나는 그들이 (XDocument 등) 훌륭하다는 데 동의하지만 OP는 C # 2.0에 대해 물었습니다.
Marc Gravell


2

.NET 3.5에서 작업 중이고 실험용 코드에 만족하지 않는 경우 LINQ to XSD ( http://blogs.msdn.com/xmlteam/archive/2008/02/21/linq-to- xsd-alpha-0-2.aspx )는 XSD에서 .NET 클래스를 생성합니다 (XSD의 기본 제공 규칙 포함).

그런 다음 XSD 규칙을 준수하는지 확인하여 파일에 직접 쓰고 파일에서 읽을 수 있습니다.

작업하는 모든 XML 문서에 대해 XSD를 사용하는 것이 좋습니다.

  • XML에서 규칙을 적용 할 수 있습니다.
  • 다른 사람들이 XML이 어떻게 구성되는지 볼 수 있습니다.
  • XML 유효성 검사에 사용할 수 있습니다.

Liquid XML Studio는 XSD 생성을위한 훌륭한 도구이며 무료입니다!


2

XmlDocument 클래스를 사용하여 XML 작성

//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으로 큰 성공을 거두었습니다. 그들은 또한 데이터베이스에 매우 친숙합니다.
User1

1

C # 프로그래머로서 제 개인적인 의견은 C #에서 XML을 처리하는 가장 좋은 방법은 코드의 해당 부분을 VB .NET 프로젝트에 위임하는 것입니다. .NET 3.5에서 VB .NET에는 XML 리터럴이있어 XML을 훨씬 더 직관적으로 처리 할 수 ​​있습니다. 예를 들어 여기를 참조하십시오.

Visual Basic의 LINQ to XML 개요

(C # 코드가 아닌 VB 코드를 표시하도록 페이지를 설정해야합니다.)

나머지 프로젝트는 C #으로 작성하지만 참조 된 VB 프로젝트에서 XML을 처리합니다.


XML 리터럴에 대해서만 vb로 전환하는 것은 가치가 없습니다. XML은 리터럴 만 처리합니다. xml이 매개 변수로 전달되는 경우 XML 리터럴 지원은 많은 이점을 제공하지 않습니다. 대신 vb.net의 레거시 구문은 C #의 행복한 프로그래밍 경험을 망칠 것입니다.
Gqqnbig

0

nyxtom,

예 1에서 "doc"와 "xdoc"가 일치하지 않아야합니까?

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

감사합니다 David. 동의합니다. 당시에는 댓글을 달 수 없습니다. 이유가 확실하지 않습니다.
mokumaxCraig

0

Cookey의 대답은 좋습니다 ...하지만 XSD (또는 XML)에서 강력한 형식의 개체를 만들고 몇 줄의 코드로 직렬화 / 역 직렬화하는 방법에 대한 자세한 지침은 다음과 같습니다.

명령


"찾으 신 페이지가 존재하지 않습니다." :(
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.