Jaki jest najlepszy sposób radzenia sobie z dokumentami XML, XSD itp. W C # 2.0?
Których klas użyć itp. Jakie są najlepsze praktyki dotyczące analizowania i tworzenia dokumentów XML itp.
EDYCJA: mile widziane są również sugestie .Net 3.5.
Jaki jest najlepszy sposób radzenia sobie z dokumentami XML, XSD itp. W C # 2.0?
Których klas użyć itp. Jakie są najlepsze praktyki dotyczące analizowania i tworzenia dokumentów XML itp.
EDYCJA: mile widziane są również sugestie .Net 3.5.
Odpowiedzi:
Podstawowe sposoby czytania i pisania w języku C # 2.0 są realizowane za pośrednictwem klasy XmlDocument . Większość ustawień można załadować bezpośrednio do XmlDocument za pośrednictwem XmlReader, które akceptuje.
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);
Uważam, że najłatwiejszym / najszybszym sposobem odczytania dokumentu XML jest użycie 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");
Jeśli potrzebujesz pracować z dokumentami XSD, aby sprawdzić poprawność dokumentu XML, możesz tego użyć.
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();
(AKTUALIZACJA 1)
W .NET 3.5 używasz XDocument do wykonywania podobnych zadań. Różnica polega jednak na tym, że masz tę zaletę, że wykonujesz zapytania Linq, aby wybrać dokładne dane, których potrzebujesz. Dzięki dodaniu inicjatorów obiektów można utworzyć zapytanie, które zwraca nawet obiekty z własnej definicji bezpośrednio w samym zapytaniu.
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();
(AKTUALIZACJA 2)
Przyjemnym sposobem w .NET 3.5 jest użycie XDocument do tworzenia XML. To sprawia, że kod pojawia się w podobny sposób do żądanego wyniku.
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")
)
)
);
tworzy
<!--Xml Document-->
<catalog>
<book id="bk001">
<title>Book Title</title>
</book>
</catalog>
Wszystko inne zawodzi, możesz zapoznać się z tym artykułem MSDN, który zawiera wiele przykładów, które tutaj omówiłem, i nie tylko. http://msdn.microsoft.com/en-us/library/aa468556.aspx
To zależy od rozmiaru; w przypadku małych i średnich plików XML DOM, taki jak XmlDocument (dowolna wersja C # / .NET) lub XDocument (.NET 3.5 / C # 3.0) jest oczywistym zwycięzcą. W przypadku korzystania z xsd można załadować plik XML przy użyciu XmlReader , a XmlReader akceptuje (do utworzenia ) XmlReaderSettings . Obiekty XmlReaderSettings mają właściwość Schemas, której można użyć do wykonania walidacji xsd (lub dtd).
W przypadku pisania xml obowiązują te same rzeczy, zauważając, że nieco łatwiej jest rozłożyć zawartość za pomocą LINQ-to-XML (XDocument) niż starszy XmlDocument.
Jednak w przypadku ogromnego pliku XML DOM może zepsuć zbyt dużo pamięci, w takim przypadku może być konieczne bezpośrednie użycie XmlReader / XmlWriter.
Na koniec do manipulowania XML możesz chcieć użyć XslCompiledTransform (warstwy xslt).
Alternatywą dla pracy z XML jest praca z modelem obiektowym; możesz użyć xsd.exe do tworzenia klas, które reprezentują model zgodny z xsd i po prostu załaduj xml jako obiekty , manipuluj nim za pomocą OO, a następnie ponownie serializuj te obiekty; robisz to za pomocą XmlSerializer .
odpowiedź nyxtom jest bardzo dobra. Dodałbym do tego kilka rzeczy:
Jeśli potrzebujesz dostępu tylko do odczytu do dokumentu XML, XPathDocument
jest to znacznie lżejszy obiekt niż XmlDocument
.
Wadą używania XPathDocument
jest to, że nie możesz używać znanych SelectNodes
i SelectSingleNode
metod XmlNode
. Zamiast tego musisz użyć narzędzi, które IXPathNavigable
zapewnia: użyj, CreateNavigator
aby utworzyć XPathNavigator
, i użyj, XPathNavigator
aby utworzyć XPathNodeIterator
s, aby iterować po listach węzłów znalezionych za pośrednictwem XPath. Zwykle wymaga to kilku wierszy kodu więcej niż XmlDocument
metody.
Ale: klasy XmlDocument
i są XmlNode
implementowane IXPathNavigable
, więc każdy kod, który napiszesz, aby użyć tych metod w pliku, XPathDocument
będzie również działał na pliku XmlDocument
. Jeśli przyzwyczaisz się do pisania przeciwko IXPathNavigable
, twoje metody mogą działać przeciwko obu obiektom. (Dlatego używanie sygnatur metod XmlNode
i XmlDocument
w jest oznaczane przez FxCop).
Żałośnie XDocument
i XElement
( XNode
i XObject
) nie wdrażają IXPathNavigable
.
Inną rzeczą, której nie ma w odpowiedzi nyxtom, jest XmlReader
. Zwykle używa się go, XmlReader
aby uniknąć narzutu związanego z analizowaniem strumienia XML do modelu obiektowego przed rozpoczęciem jego przetwarzania. Zamiast tego używaszXmlReader
do przetwarzania strumienia wejściowego jednego węzła XML na raz. To jest zasadniczo odpowiedź .NET na SAX. Pozwala pisać bardzo szybki kod do przetwarzania bardzo dużych dokumentów XML.
XmlReader
zapewnia również najprostszy sposób przetwarzania fragmentów dokumentów XML, np. strumień elementów XML bez elementu kodującego, który zwraca opcja FOR XML RAW programu SQL Server.
Kod, którego używasz, XmlReader
jest zazwyczaj bardzo ściśle powiązany z formatem czytanego XML. Używanie XPath pozwala na dużo, dużo luźniejsze powiązanie twojego kodu z XML, dlatego jest to zazwyczaj właściwa odpowiedź. Ale kiedy potrzebujesz użyć XmlReader
, naprawdę tego potrzebujesz.
XPathNavigator CreateNavigator(this XNode node)
do tworzenia XPathNavigator
an XNode
(która zawiera klasę pochodną XDocument
).
Przede wszystkim poznaj nowe klasy XDocument i XElement , ponieważ są one ulepszeniem w stosunku do poprzedniej rodziny XmlDocument.
Jednak może być konieczne używanie starych klas do pracy ze starszym kodem - w szczególności z wcześniej wygenerowanymi serwerami proxy. W takim przypadku będziesz musiał zapoznać się z niektórymi wzorcami współdziałania między tymi klasami obsługi XML.
Myślę, że twoje pytanie jest dość szerokie i wymagałoby zbyt wiele w jednej odpowiedzi, aby podać szczegóły, ale jest to pierwsza ogólna odpowiedź, o której pomyślałem, i służy jako początek.
101 próbek Linq
http://msdn.microsoft.com/en-us/library/bb387098.aspx
i próbki Linq do XML
http://msdn.microsoft.com/en-us/vbasic/bb688087.aspx
Myślę, że Linq ułatwia XML.
Jeśli pracujesz w .NET 3.5 i nie boisz się eksperymentalnego kodu, możesz sprawdzić LINQ to XSD ( http://blogs.msdn.com/xmlteam/archive/2008/02/21/linq-to- xsd-alpha-0-2.aspx ), który wygeneruje klasy .NET z XSD (w tym wbudowane reguły z XSD).
Ma wtedy możliwość zapisu bezpośrednio do pliku i odczytu z pliku, zapewniając zgodność z regułami XSD.
Zdecydowanie sugeruję mieć XSD dla każdego dokumentu XML, z którym pracujesz:
Uważam, że Liquid XML Studio to świetne narzędzie do generowania XSD i jest darmowe!
Pisanie kodu XML za pomocą klasy 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>
Jeśli utworzysz zbiór danych o typie strukturalnym w projektancie, automatycznie otrzymasz xsd, obiekt o jednoznacznie określonym typie, i możesz załadować i zapisać plik xml za pomocą jednej linii kodu.
Osobiście uważam, że jako programista C # najlepszym sposobem radzenia sobie z XML w C # jest delegowanie tej części kodu do projektu VB .NET. W .NET 3.5, VB .NET ma XML Literals, dzięki czemu obsługa XML jest znacznie bardziej intuicyjna. Zobacz tutaj, na przykład:
Omówienie LINQ to XML w Visual Basic
(Pamiętaj, aby ustawić stronę do wyświetlania kodu VB, a nie kodu C #).
Resztę projektu napisałbym w C #, ale obsłużę XML w przywoływanym projekcie VB.
nyxtom,
Czy „doc” i „xdoc” nie powinny pasować do przykładu 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();
Odpowiedź Cookey jest dobra ... ale tutaj są szczegółowe instrukcje, jak utworzyć obiekt o jednoznacznie określonym typie z XSD (lub XML) i serializować / deserializować w kilku wierszach kodu:
Jeśli kiedykolwiek będziesz musiał konwertować dane między XmlNode
<=> XNode
<=> XElement
(np. W celu korzystania z LINQ), te rozszerzenia mogą być dla Ciebie pomocne:
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);
}
}
Stosowanie:
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
...