¿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 para analizar y crear documentos XML, etc.?
EDITAR: Las sugerencias de .Net 3.5 también son bienvenidas.
¿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 para analizar y crear documentos XML, etc.?
EDITAR: Las sugerencias de .Net 3.5 también son bienvenidas.
Respuestas:
El medio principal de lectura y escritura en C # 2.0 se realiza a través de la clase XmlDocument . Puede cargar la mayoría de sus configuraciones directamente en XmlDocument a través del XmlReader que acepta.
XmlDocument document = new XmlDocument();
document.LoadXml("<People><Person Name='Nick' /><Person Name='Joe' /></People>");
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);
Encuentro que la forma más fácil / rápida de leer un documento XML es utilizando XPath.
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 usar esto.
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); }
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
}
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 Linq para seleccionar los datos exactos que necesita. Con la adición de inicializadores de objetos, puede crear una consulta que incluso devuelva objetos de su propia definición directamente en la 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();
(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
Depende del tamaño; para xml de tamaño pequeño a mediano, un DOM como XmlDocument (cualquier versión de 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 una propiedad Schemas que se puede usar para realizar la validación xsd (o dtd).
Para escribir xml, se aplican las mismas cosas, teniendo en cuenta que es un poco más fácil diseñar contenido con LINQ-to-XML (XDocument) que con XmlDocument anterior.
Sin embargo, para xml de gran tamaño, un DOM puede consumir demasiada memoria, en cuyo caso es posible que deba usar XmlReader / XmlWriter directamente.
Finalmente, para manipular xml, es posible que desee utilizar XslCompiledTransform (una capa xslt).
La alternativa a trabajar con xml es trabajar con un modelo de objetos; puede 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 .
La respuesta de nyxtom es muy buena. Le agregaría un par de cosas:
Si necesita acceso de solo lectura a un documento XML, XPathDocument
es un objeto mucho más liviano que XmlDocument
.
La desventaja de usar XPathDocument
es que no se puede utilizar el familiar SelectNodes
y SelectSingleNode
métodos de XmlNode
. En su lugar, debe usar las herramientas que IXPathNavigable
proporciona: use CreateNavigator
para crear un XPathNavigator
, y use XPathNavigator
para crear XPathNodeIterator
s para iterar sobre las listas de nodos que encuentre a través de XPath. Esto generalmente requiere algunas líneas más de código que los XmlDocument
métodos.
Pero: las clases XmlDocument
y XmlNode
se implementan IXPathNavigable
, por lo que cualquier código que escriba para usar esos métodos en un XPathDocument
también funcionará en un XmlDocument
. Si te acostumbras a escribir en contra IXPathNavigable
, tus métodos pueden funcionar contra cualquier objeto. (Esta es la razón por la que FxCop marca el uso de XmlNode
y XmlDocument
en las firmas de métodos).
Lamentablemente, XDocument
y XElement
( XNode
y XObject
) no se implementan IXPathNavigable
.
Otra cosa que no está presente en la respuesta de nyxtom es XmlReader
. Por lo general, se usa XmlReader
para evitar la sobrecarga de analizar el flujo XML en un modelo de objeto antes de comenzar a procesarlo. En su lugar, utiliza un XmlReader
para procesar el flujo 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 sencilla de procesar fragmentos de documentos XML, por ejemplo, el flujo de elementos XML sin ningún elemento adjunto que devuelve la opción FOR XML RAW de SQL Server.
El código que escribe utilizando XmlReader
generalmente está muy estrechamente acoplado al formato del XML que está leyendo. El uso de XPath permite que su código esté mucho más acoplado al XML, por lo que generalmente es la respuesta correcta. Pero cuando lo necesita XmlReader
, realmente lo necesita.
XPathNavigator CreateNavigator(this XNode node)
para crear un XPathNavigator
desde un XNode
(que incluye la clase derivada XDocument
).
En primer lugar, conozca las nuevas clases XDocument y XElement , porque son una mejora con respecto a la familia XmlDocument anterior.
Sin embargo , es posible que deba seguir usando las clases antiguas para trabajar con código heredado, en particular los proxies generados anteriormente. 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 como un comienzo.
101 muestras de Linq
http://msdn.microsoft.com/en-us/library/bb387098.aspx
y Linq to XML samples
http://msdn.microsoft.com/en-us/vbasic/bb688087.aspx
Y creo que Linq facilita XML.
Si está trabajando en .NET 3.5 y no le teme al código experimental, puedes consultar LINQ to XSD ( http://blogs.msdn.com/xmlteam/archive/2008/02/21/linq-to- xsd-alpha-0-2.aspx ) que generará clases .NET a partir de 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 cumpla con las reglas XSD.
Definitivamente sugiero tener un XSD para cualquier documento XML con el que trabaje:
¡Encuentro que Liquid XML Studio es una gran herramienta para generar XSD y es gratis!
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>
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 a un proyecto de VB .NET. En .NET 3.5, VB .NET tiene XML Literals, lo que hace que el manejo de 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.
nyxtom,
¿No deberían coincidir "doc" y "xdoc" en el Ejemplo 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();
La respuesta de Cookey es buena ... pero aquí hay instrucciones detalladas sobre cómo crear un objeto fuertemente tipado a partir de un XSD (o XML) y serializar / deserializar en unas pocas líneas de código:
Si alguna vez necesita convertir datos entre XmlNode
<=> XNode
<=> XElement
(por ejemplo, para usar LINQ), estas Extensiones pueden ser útiles para usted:
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
...