Como lidar com XML em C #


87

Qual é a melhor maneira de lidar com documentos XML, XSD etc. em C # 2.0?

Quais classes usar etc. Quais são as melhores práticas de análise e criação de documentos XML, etc.

EDIT: .Net 3.5 sugestões também são bem-vindas.


1
Para aqueles que também estão tentando encontrar uma solução mais viável, ignore isso. É uma biblioteca .NET antiga. Em vez disso, use o XDocument, e você evitará que arrancar seus olhos de frustração
AER

Respostas:


180

O principal meio de leitura e gravação em C # 2.0 é feito por meio da classe XmlDocument . Você pode carregar a maioria de suas configurações diretamente no XmlDocument por meio do XmlReader que ele aceita.

Carregando XML diretamente

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

Carregando XML de um arquivo

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

Acho que a maneira mais fácil / rápida de ler um documento XML é usando XPath.

Lendo um documento XML usando XPath (usando XmlDocument que nos permite editar)

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

Se você precisa trabalhar com documentos XSD para validar um documento XML, você pode usar isso.

Validando documentos XML em relação a esquemas XSD

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

Validando XML contra XSD em cada Nó (ATUALIZAÇÃO 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
}

Escrevendo um documento XML (manualmente)

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

(ATUALIZAÇÃO 1)

No .NET 3.5, você usa o XDocument para executar tarefas semelhantes. A diferença, entretanto, é que você tem a vantagem de realizar Consultas Linq para selecionar os dados exatos de que precisa. Com a adição de inicializadores de objeto, você pode criar uma consulta que retorna até mesmo objetos de sua própria definição diretamente na própria consulta.

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

(ATUALIZAÇÃO 2)

Uma boa maneira no .NET 3.5 é usar o XDocument para criar XML abaixo. Isso faz com que o código apareça em um padrão semelhante à saída desejada.

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

cria

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

Se tudo o mais falhar, você pode verificar este artigo do MSDN que tem muitos exemplos que discuti aqui e mais. http://msdn.microsoft.com/en-us/library/aa468556.aspx


3
Você pode querer apontar que está usando o XDocument no último exemplo, pois o XDocument é bastante diferente do XmlDocument
Aaron Powell,

2
Correção; não há C # 3.5; você quer dizer .NET 3.5 e C # 3.0
Marc Gravell

ah, e os [inicializadores de objeto] "on the fly" funcionariam basicamente da mesma forma com C # 3.0 e XmlDocument - ainda uma boa resposta, embora (+1)
Marc Gravell

Vale a pena mencionar que se você estiver carregando um documento para consultar com XPath (e não para editar), usar um XPathDocument será muito mais eficiente
Oliver Hallam

Esta validação de esquema é feita nó por nó? Se não, existe uma maneira de fazer isso nó por nó?
Malik Daud Ahmad Khokhar

30

Depende do tamanho; para xml de tamanho pequeno a médio, um DOM como XmlDocument (qualquer versão C # /. NET) ou XDocument (.NET 3.5 / C # 3.0) é o vencedor óbvio. Para usar o xsd, você pode carregar o xml usando um XmlReader , e um XmlReader aceita (para criar ) um XmlReaderSettings . Os objetos XmlReaderSettings têm uma propriedade Schemas que pode ser usada para executar a validação xsd (ou dtd).

Para escrever xml, as mesmas coisas se aplicam, observando que é um pouco mais fácil fazer o layout do conteúdo com LINQ-to-XML (XDocument) do que o XmlDocument mais antigo.

No entanto, para xml enorme, um DOM pode consumir muita memória e, nesse caso, você pode precisar usar XmlReader / XmlWriter diretamente.

Finalmente, para manipular xml, você pode querer usar XslCompiledTransform (uma camada xslt).

A alternativa para trabalhar com xml é trabalhar com um modelo de objeto; você pode usar xsd.exe para criar classes que representam um modelo compatível com xsd e simplesmente carregar o xml como objetos , manipulá-lo com OO e serializar esses objetos novamente; você faz isso com XmlSerializer .


Para manipular (adicionar / suprimir elementos) um grande documento XML (40k linhas). Qual é a melhor maneira? Eu costumava usar LINQ-to-XML.
Neyoh

12

A resposta da nyxtom é muito boa. Eu adicionaria algumas coisas a ele:

Se você precisar de acesso somente leitura a um documento XML, XPathDocumenté um objeto muito mais leve do que XmlDocument.

A desvantagem de usar XPathDocumenté que você não pode usar os métodos SelectNodese SelectSingleNodemétodos familiares de XmlNode. Em vez disso, você deve usar as ferramentas que o IXPathNavigablefornece: use CreateNavigatorpara criar um XPathNavigatore use XPathNavigatorpara criar XPathNodeIterators para iterar nas listas de nós que você encontrar por meio do XPath. Isso geralmente requer mais algumas linhas de código do que os XmlDocumentmétodos.

Mas: as classes XmlDocumente XmlNodeimplementam IXPathNavigable, portanto, qualquer código que você escrever para usar esses métodos em um XPathDocumenttambém funcionará em um XmlDocument. Se você se acostumar a escrever contra IXPathNavigable, seus métodos podem funcionar contra qualquer um dos objetos. (É por isso que usar XmlNodee XmlDocumentem assinaturas de método é sinalizado pelo FxCop.)

Lamentavelmente, XDocumentand XElement(and XNodeand XObject) não implementam IXPathNavigable.

Outra coisa que não está presente na resposta de nyxtom é XmlReader. Você geralmente usa XmlReaderpara evitar a sobrecarga de analisar o fluxo XML em um modelo de objeto antes de começar a processá-lo. Em vez disso, use um XmlReaderpara processar o fluxo de entrada um nó XML por vez. Esta é essencialmente a resposta do .NET para SAX. Ele permite que você escreva um código muito rápido para processar documentos XML muito grandes.

XmlReader também fornece a maneira mais simples de processar fragmentos de documentos XML, por exemplo, o fluxo de elementos XML sem nenhum elemento de inclusão que a opção FOR XML RAW do SQL Server retorna.

O código que você escreve usando XmlReadergeralmente está fortemente acoplado ao formato do XML que está lendo. Usar XPath permite que seu código seja muito, muito mais vagamente acoplado ao XML, e é por isso que geralmente é a resposta certa. Mas quando você precisa usar XmlReader, você realmente precisa.


3
Observe que há um método de extensão XPathNavigator CreateNavigator(this XNode node)para criar um XPathNavigatorde um XNode(que inclui a classe derivada XDocument).
Dave

5

Em primeiro lugar, conheça as novas classes XDocument e XElement , porque são uma melhoria em relação à família XmlDocument anterior.

  1. Eles funcionam com LINQ
  2. Eles são mais rápidos e mais leves

No entanto , talvez você ainda precise usar as classes antigas para trabalhar com código legado - particularmente proxies gerados anteriormente. Nesse caso, você precisará se familiarizar com alguns padrões para interoperar entre essas classes de manipulação de XML.

Acho que sua pergunta é bastante ampla e exigiria muito em uma única resposta para fornecer detalhes, mas esta é a primeira resposta geral em que pensei e serve como um começo.


Eu concordo que eles (XDocument etc) são ótimos, mas o OP perguntou sobre C # 2.0.
Marc Gravell


2

Se você está trabalhando em .NET 3.5 e não tem medo de código experimental, pode verificar LINQ to XSD ( http://blogs.msdn.com/xmlteam/archive/2008/02/21/linq-to- xsd-alpha-0-2.aspx ) que irá gerar classes .NET a partir de um XSD (incluindo regras embutidas do XSD).

Em seguida, ele tem a capacidade de gravar diretamente em um arquivo e ler de um arquivo, garantindo que ele esteja em conformidade com as regras XSD.

Definitivamente, sugiro ter um XSD para qualquer documento XML com o qual você trabalha:

  • Permite que você aplique regras no XML
  • Permite que outros vejam como o XML está / será estruturado
  • Pode ser usado para validação de XML

Acho que Liquid XML Studio é uma ótima ferramenta para gerar XSDs e é grátis!


2

Escrevendo XML com a classe 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

Se você criar um conjunto de dados tipado no designer, obterá automaticamente um xsd, um objeto fortemente tipado, e poderá carregar e salvar o xml com uma linha de código.


Tive grande sucesso com o DataSet. Eles também são muito amigáveis ​​com bancos de dados.
Usuário1

1

Minha opinião pessoal, como programador C #, é que a melhor maneira de lidar com XML em C # é delegar essa parte do código a um projeto VB .NET. No .NET 3.5, o VB .NET possui XML Literals, o que torna o tratamento de XML muito mais intuitivo. Veja aqui, por exemplo:

Visão geral do LINQ to XML no Visual Basic

(Certifique-se de definir a página para exibir o código VB, não o código C #.)

Eu escreveria o resto do projeto em C #, mas lidaria com o XML em um projeto VB referenciado.


Não vale a pena mudar para vb apenas para XML literal. XML lida apenas com literais. Se o xml for passado como um parâmetro, o suporte literal XML não oferece muitos benefícios. Em vez disso, a sintaxe legada do vb.net arruinará a feliz experiência de programação do C #.
Gqqnbig

0

nyxtom,

"Doc" e "xdoc" não deveriam corresponder no Exemplo 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();

Enviei uma edição para aprovação da resposta à qual você está se referindo; no entanto, deveria ser um comentário, não uma resposta.
David Thompson

Obrigado David. Concordo, não me permitiria comentar na época. Não sei por quê.
mokumaxCraig

0

A resposta de Cookey é boa ... mas aqui estão instruções detalhadas sobre como criar um objeto fortemente tipado a partir de um XSD (ou XML) e serializar / desserializar em algumas linhas de código:

Instruções


"A página que você estava procurando não existe." :(
Ian Grainger,

0

Se você precisar converter dados entre XmlNode<=> XNode<=> XElement
(por exemplo, para usar o LINQ), essas extensões podem ser úteis para você:

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

Uso:

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
...
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.