Pregunta Cómo lidiar con XML en C #


¿Cuál es la mejor manera de tratar con documentos XML, XSD, etc. en C # 2.0?

Qué clases usar, etc. ¿Cuáles son las mejores prácticas de análisis y creación de documentos XML, etc.

EDIT: sugerencias de .Net 3.5 también son bienvenidas.


75
2017-10-21 05:35


origen


Respuestas:


El medio principal de leer y escribir en C # 2.0 se hace a través del XmlDocument clase. Puede cargar la mayoría de sus configuraciones directamente en XmlDocument a través del XmlReader que acepta.

Cargando XML directamente

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

Cargando XML desde un archivo

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

La forma más fácil / rápida de leer un documento XML es usando XPath.

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

Si necesita trabajar con documentos XSD para validar un documento XML, puede usarlo.

Validar documentos XML contra 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); }

Validación de XML contra XSD en cada nodo (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
}

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

(ACTUALIZACIÓN 1)

En .NET 3.5, usa XDocument para realizar tareas similares. Sin embargo, la diferencia es que tiene la ventaja de realizar consultas de Linq para seleccionar los datos exactos que necesita. Con la adición de los inicializadores de objetos, puede crear una consulta que incluso devuelva objetos de su propia definición directamente en la consulta misma.

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

(ACTUALIZACIÓN 2)

Una buena forma en .NET 3.5 es usar XDocument para crear XML a continuación. Esto hace que el código aparezca en un patrón similar al resultado deseado.

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

crea

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

Todo lo demás falla, puede consultar este artículo de MSDN que tiene muchos ejemplos que he discutido aquí y más. http://msdn.microsoft.com/en-us/library/aa468556.aspx


165
2017-10-21 06:40



Depende del tamaño; para xml de tamaño pequeño a mediano, un DOM como XmlDocument (cualquier versión C # / .NET) o XDocument (.NET 3.5 / C # 3.0) es el ganador obvio. Para usar xsd, puede cargar xml usando un XmlReader, y un XmlReader acepta (para Crear) un XmlReaderSettings. Los objetos XmlReaderSettings tienen un Schemas propiedad que se puede usar para realizar la validación de xsd (o dtd).

Para escribir xml, se aplican las mismas cosas, señalando que es un poco más fácil diseñar contenido con LINQ-a-XML (XDocument) que el antiguo XmlDocument.

Sin embargo, para xml enorme, un DOM puede consumir demasiada memoria, en cuyo caso es posible que necesite usar XmlReader / XmlWriter directamente.

Finalmente, para manipular xml, es posible que desee utilizar XslCompiledTransform (una capa xslt).

La alternativa para trabajar con xml es trabajar con un modelo de objetos; puedes usar xsd.exe para crear clases que representen un modelo compatible con xsd, y simplemente cargar el xml como objetos, manipularlo con OO, y luego serializar esos objetos nuevamente; haces esto con XmlSerializer.


29
2017-10-21 05:43



La respuesta de Nyxtom es muy buena. Le agregaría un par de cosas:

Si necesita acceso de solo lectura a un documento XML, XPathDocumentes un objeto mucho más ligero que XmlDocument.

La desventaja de usar XPathDocument es que no puedes usar lo familiar SelectNodes y SelectSingleNode métodos de XmlNode. En cambio, debe usar las herramientas que el IXPathNavigable proporciona: uso CreateNavigator para crear un XPathNavigatory usa el XPathNavigator crear XPathNodeIterators para iterar sobre las listas de nodos que encuentre a través de XPath. Esto generalmente requiere unas pocas líneas más de código que el XmlDocument métodos.

Pero el XmlDocument y XmlNode clases implementar IXPathNavigable, por lo que cualquier código que escriba use esos métodos en un XPathDocument también trabajará en una XmlDocument. Si te acostumbras a escribir en contra IXPathNavigable, tus métodos pueden funcionar contra cualquier objeto. (Esta es la razón por la cual XmlNode y XmlDocument en las firmas de método está marcado por FxCop).

Lamentablemente, XDocument y XElement (y XNode y XObject) no implementar IXPathNavigable.

Otra cosa que no está presente en la respuesta de Nyxtom es XmlReader. Generalmente usas XmlReader para evitar la sobrecarga de analizar el flujo XML en un modelo de objetos antes de comenzar a procesarlo. En cambio, usas un XmlReader para procesar la secuencia de entrada un nodo XML a la vez. Esta es esencialmente la respuesta de .NET a SAX. Le permite escribir código muy rápido para procesar documentos XML muy grandes.

XmlReader también proporciona la forma más simple de procesar fragmentos de documentos XML, p. la secuencia de elementos XML sin elemento de envolvente que devuelve la opción FOR XML RAW de SQL Server.

El código que escribes usando XmlReader generalmente está muy unido al formato del XML que está leyendo. El uso de XPath permite que su código se acople mucho más libremente al XML, por lo que generalmente es la respuesta correcta. Pero cuando necesitas usar XmlReader, realmente lo necesitas


12
2017-10-21 18:51



101 muestras de Linq

http://msdn.microsoft.com/en-us/library/bb387098.aspx

y Linq a muestras XML

http://msdn.microsoft.com/en-us/vbasic/bb688087.aspx

Y creo que Linq simplifica XML.


4
2017-10-21 06:51



Antes que nada, conozca el nuevo XDocument y XElement clases, porque son una mejora sobre la familia XmlDocument anterior.

  1. Ellos trabajan con LINQ
  2. Son más rápidos y más livianos

sin embargo, es posible que deba seguir utilizando las clases antiguas para trabajar con el código heredado, en particular los proxies generados previamente. En ese caso, deberá familiarizarse con algunos patrones para interoperar entre estas clases de manejo de XML.

Creo que su pregunta es bastante amplia y requeriría demasiado en una sola respuesta para dar detalles, pero esta es la primera respuesta general en la que pensé, y sirve de inicio.


3
2017-10-21 05:47



Si está trabajando en .NET 3.5 y no tiene miedo del código experimental, puede consultar LINQ to XSD (http://blogs.msdn.com/xmlteam/archive/2008/02/21/linq-to-xsd-alpha-0-2.aspx) que generará clases .NET desde un XSD (incluidas las reglas integradas del XSD).

Luego tiene la capacidad de escribir directamente en un archivo y leer desde un archivo, asegurándose de que se ajuste a las reglas de XSD.

Definitivamente sugiero tener un XSD para cualquier documento XML con el que trabajes:

  • Le permite aplicar reglas en el XML
  • Permite a otros ver cómo está estructurado / estructurado el XML
  • Puede ser utilizado para la validación de XML

Me parece que Liquid XML Studio es una gran herramienta para generar XSD y ¡es gratis!


2
2017-10-21 06:49



Si crea un conjunto de datos tipeados en el diseñador, obtendrá automáticamente un xsd, un objeto fuertemente tipado, y puede cargar y guardar el xml con una línea de código.


1
2017-10-21 16:41



Mi opinión personal, como programador de C #, es que la mejor manera de tratar con XML en C # es delegar esa parte del código en un proyecto .NET de VB. En .NET 3.5, VB .NET tiene XML Literals, lo que hace que manejar XML sea mucho más intuitivo. Vea aquí, por ejemplo:

Descripción general de LINQ to XML en Visual Basic

(Asegúrese de configurar la página para que muestre el código VB, no el código C #).

Escribiría el resto del proyecto en C #, pero manejaría el XML en un proyecto VB referenciado.


1
2018-03-31 18:57



Escribir XML con la clase 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
2018-02-09 10:18