Quelle est la meilleure façon de traiter les documents XML, XSD, etc. en C # 2.0?
Quelles classes utiliser, etc. Quelles sont les meilleures pratiques d'analyse et de création de documents XML, etc.
EDIT: Les suggestions .Net 3.5 sont également les bienvenues.
Le moyen principal de lecture et d'écriture en C # 2.0 est effectué via la classe XmlDocument . Vous pouvez charger la plupart de vos paramètres directement dans XmlDocument via XmlReader qu'il accepte.
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);
Je trouve que le moyen le plus simple et le plus rapide de lire un document XML consiste à utiliser 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 vous devez utiliser des documents XSD pour valider un document XML, vous pouvez l'utiliser.
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();
(UPDATE 1)
Dans .NET 3.5, vous utilisez XDocument pour effectuer des tâches similaires. Cependant, la différence est que vous avez l’avantage d’effectuer des requêtes Linq pour sélectionner les données exactes dont vous avez besoin. Avec l'ajout d'initialiseurs d'objet, vous pouvez créer une requête qui retourne même des objets de votre propre définition directement dans la requête elle-même.
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();
(UPDATE 2)
Une manière intéressante de .NET 3.5 consiste à utiliser XDocument pour créer du XML ci-dessous. Cela fait apparaître le code selon un modèle similaire à la sortie souhaitée.
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")
)
)
);
crée
<!--Xml Document-->
<catalog>
<book id="bk001">
<title>Book Title</title>
</book>
</catalog>
Tout le reste échoue, vous pouvez consulter cet article MSDN qui contient de nombreux exemples dont j'ai déjà parlé et bien plus encore. http://msdn.Microsoft.com/en-us/library/aa468556.aspx
Cela dépend de la taille; pour les xml de taille petite à moyenne, un DOM tel que XmlDocument (toutes versions C #/.NET) ou XDocument (.NET 3.5/C # 3.0) est le gagnant évident. Pour utiliser xsd, vous pouvez charger xml avec un XmlReader , et un XmlReader accepte (de Créer ) un XmlReaderSettings . Les objets XmlReaderSettings ont une propriété Schemas qui peut être utilisée pour effectuer une validation xsd (ou dtd).
Pour l'écriture XML, les mêmes choses s'appliquent, notant qu'il est un peu plus facile de mettre en forme le contenu avec LINQ-to-XML (XDocument) que l'ancien XmlDocument.
Toutefois, pour les fichiers XML volumineux, un DOM peut traiter trop de mémoire, auquel cas vous devrez peut-être utiliser directement XmlReader/XmlWriter.
Enfin, pour manipuler XML, vous souhaiterez peut-être utiliser XslCompiledTransform (un calque xslt).
L'alternative au travail avec XML est de travailler avec un modèle d'objet; vous pouvez utiliser xsd.exe pour créer des classes représentant un modèle conforme à xsd, et simplement charger xml as objects, le manipuler avec OO, puis sérialiser à nouveau ces objets; vous faites cela avec XmlSerializer .
la réponse de nyxtom est très bonne. J'ajouterais quelques éléments à cela:
Si vous avez besoin d'un accès en lecture seule à un document XML, XPathDocument
est un objet beaucoup plus léger que XmlDocument
.
L'inconvénient de l'utilisation de XPathDocument
est que vous ne pouvez pas utiliser les méthodes SelectNodes
et SelectSingleNode
bien connues de XmlNode
. A la place, vous devez utiliser les outils fournis par IXPathNavigable
: utilisez CreateNavigator
pour créer une XPathNavigator
et utilisez XPathNavigator
pour créer XPathNodeIterator
s afin de parcourir les listes de nœuds trouvées via XPath. Cela nécessite généralement quelques lignes de code de plus que les méthodes XmlDocument
.
Mais: les classes XmlDocument
et XmlNode
implémentent IXPathNavigable
, ainsi tout code que vous écrivez pour utiliser ces méthodes sur une XPathDocument
fonctionnera également sur une XmlDocument
. Si vous vous habituez à écrire contre IXPathNavigable
, vos méthodes peuvent fonctionner avec l'un ou l'autre objet. (C’est pourquoi l’utilisation de XmlNode
et XmlDocument
dans les signatures de méthodes est marquée par FxCop.)
Malheureusement, XDocument
et XElement
(et XNode
et XObject
) n'implémentent pas IXPathNavigable
.
Une autre chose absente de la réponse de nyxtom est XmlReader
. Vous utilisez généralement XmlReader
pour éviter la surcharge liée à l'analyse du flux XML dans un modèle objet avant de commencer à le traiter. A la place, vous utilisez une variable XmlReader
pour traiter le noeud d'entrée du flux d'entrée à la fois. C’est essentiellement la réponse de .NET à SAX. Il vous permet d’écrire du code très rapide pour traiter des documents XML très volumineux.
XmlReader
fournit également le moyen le plus simple de traiter des fragments de document XML, par exemple. le flux d'éléments XML sans élément englobant renvoyé par l'option FOR XML RAW de SQL Server.
Le code que vous écrivez en utilisant XmlReader
est généralement très étroitement lié au format du XML qu'il lit. L'utilisation de XPath permet à votre code d'être couplé beaucoup plus librement au XML, raison pour laquelle il s'agit généralement de la bonne réponse. Mais lorsque vous devez utiliser XmlReader
, vous en avez vraiment besoin.
101 échantillons de Linq
http://msdn.Microsoft.com/en-us/library/bb387098.aspx
et exemples Linq to XML
http://msdn.Microsoft.com/en-us/vbasic/bb688087.aspx
Et je pense que Linq rend XML facile.
Tout d'abord, familiarisez-vous avec les nouvelles classes XDocument et XElement , car elles constituent une amélioration par rapport à la famille précédente de XmlDocument.
Cependant , il se peut que vous deviez quand même utiliser les anciennes classes pour travailler avec du code hérité, notamment les proxies précédemment générés. Dans ce cas, vous devrez vous familiariser avec certains modèles d'interopérabilité entre ces classes de traitement XML.
Je pense que votre question est assez large et qu’il faudrait trop de réponses dans une seule réponse pour donner des détails, mais c’est la première réponse générale à laquelle je pensais, et sert de point de départ.
Si vous travaillez dans .NET 3.5 et que vous n'avez pas peur du code expérimental, vous pouvez vérifier LINQ to XSD ( http://blogs.msdn.com/xmlteam/archive/2008/02/21/linq- to-xsd-alpha-0-2.aspx ) qui générera des classes .NET à partir d'un XSD (y compris les règles intégrées du XSD).
Il est ensuite en mesure d'écrire directement dans un fichier et de le lire à partir d'un fichier en s'assurant qu'il est conforme aux règles XSD.
Je suggère définitivement d'avoir un XSD pour tout document XML avec lequel vous travaillez:
Je trouve que Liquid XML Studio est un excellent outil pour générer des fichiers XSD. C'est gratuit!
Mon opinion personnelle, en tant que programmeur C #, est que le meilleur moyen de gérer XML en C # est de déléguer cette partie du code à un projet VB .NET. Dans .NET 3.5, VB .NET possède des littéraux XML, ce qui rend l'utilisation de XML beaucoup plus intuitive. Voir ici, par exemple:
Présentation de LINQ to XML dans Visual Basic
(Veillez à configurer la page pour afficher le code VB, pas le code C #.)
J'écrirais le reste du projet en C #, mais gérerais le XML dans un projet référencé VB.
Écrire du XML avec la 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>
Si vous créez un ensemble de données typé dans le concepteur, vous obtenez automatiquement un xsd, un objet fortement typé, et pouvez charger et enregistrer le xml avec une ligne de code.
Si vous avez besoin de convertir des données entre XmlNode
<=> XNode
<=> XElement
(par exemple pour utiliser LINQ) ces extensions peuvent vous être utiles:
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);
}
}
Usage:
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
...
La réponse de Cookey est bonne ... mais voici des instructions détaillées sur la création d'un objet fortement typé à partir d'un fichier XSD (ou XML) et la sérialisation/désérialisation en quelques lignes de code:
nyxtom,
"Doc" et "xdoc" ne devraient-ils pas correspondre dans l'exemple 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();