Jak mogę zbudować XML w C #?

438

Jak mogę wygenerować prawidłowy kod XML w języku C #?

Dan Esparza
źródło

Odpowiedzi:

510

To zależy od scenariusza. XmlSerializerjest z pewnością jednym ze sposobów i ma tę zaletę, że mapuje bezpośrednio na model obiektowy. W .NET 3.5 XDocumentitd. Są również bardzo przyjazne. Jeśli rozmiar jest bardzo duży, XmlWriterto twój przyjaciel.

Na XDocumentprzykład:

Console.WriteLine(
    new XElement("Foo",
        new XAttribute("Bar", "some & value"),
        new XElement("Nested", "data")));

Lub to samo z XmlDocument:

XmlDocument doc = new XmlDocument();
XmlElement el = (XmlElement)doc.AppendChild(doc.CreateElement("Foo"));
el.SetAttribute("Bar", "some & value");
el.AppendChild(doc.CreateElement("Nested")).InnerText = "data";
Console.WriteLine(doc.OuterXml);

Jeśli piszesz duży strumień danych, każde podejście DOM (takie jak XmlDocument/ XDocumentitp.) Szybko zajmie dużo pamięci. Więc jeśli piszesz plik XML 100 MB z CSV , możesz rozważyć XmlWriter; jest to bardziej prymitywne (wężyk jednorazowy zapisu), ale bardzo wydajne (wyobraź sobie dużą pętlę tutaj):

XmlWriter writer = XmlWriter.Create(Console.Out);
writer.WriteStartElement("Foo");
writer.WriteAttributeString("Bar", "Some & value");
writer.WriteElementString("Nested", "data");
writer.WriteEndElement();

Wreszcie przez XmlSerializer:

[Serializable]
public class Foo
{
    [XmlAttribute]
    public string Bar { get; set; }
    public string Nested { get; set; }
}
...
Foo foo = new Foo
{
    Bar = "some & value",
    Nested = "data"
};
new XmlSerializer(typeof(Foo)).Serialize(Console.Out, foo);

To dobry model do mapowania na klasy itp .; jednak może to być przesada, jeśli robisz coś prostego (lub jeśli pożądany kod XML tak naprawdę nie ma bezpośredniej korelacji z modelem obiektowym). Innym problemem XmlSerializerjest to, że nie lubi serializować niezmiennych typów: wszystko musi mieć publiczny getter i setter (chyba że zrobisz to wszystko przez wdrożenie IXmlSerializable, w którym to przypadku nie zyskałeś wiele za pomocą XmlSerializer).

Marc Gravell
źródło
10
Nie zapomnij o XStreamingElement, msdn.microsoft.com/en-us/library/… . :)
Todd White
1
W przykładzie XmlWriter ważne jest, aby pamiętać, że musisz zamknąć program piszący na końcu, aby działał poprawnie - writer.Close () jest potrzebny po funkcji writer.WriteEndElement ().
Marko,
To prawda, co mówi @Marko: Ważne jest, aby poprawnie zamknąć pisarza. Istnieje również inny sposób, aby to zrobić, zamiast bezpośrednio wywoływać writer.Close (). Możesz zawinąć wywołanie Create () w instrukcji using w następujący sposób: using (XmlWriter writer = XmlWriter.Create (Console.Out)) {writer.WriteStartElement („Foo”); itp.} Jest jeszcze inny (nieco bardziej ulepszony) przykład XmlWriter tutaj: dotnetperls.com/xmlwriter
Morten
@Morten Upewnij się, że jeśli XmlWriter implementuje IDisposable, najlepszym rozwiązaniem jest użycie instrukcji.
Marko,
Dobry stary XMLDocument ma to wszystko. Proste, proste i jasne, jeśli tworzysz dokument XML.
FrenkyB
60

Najlepszą rzeczą, jaką wypróbowałem, jest LINQ do XSD (co jest nieznane większości programistów). Dajesz mu schemat XSD, który generuje doskonale odwzorowany kompletny model obiektowy o silnym typie (oparty na LINQ na XML) w tle, który jest naprawdę łatwy w obsłudze - i aktualizuje i weryfikuje twój model obiektowy i XML w czas rzeczywisty. Mimo że nadal jest to „Preview”, nie napotkałem żadnych błędów.

Jeśli masz schemat XSD, który wygląda następująco:

  <xs:element name="RootElement">
     <xs:complexType>
      <xs:sequence>
        <xs:element name="Element1" type="xs:string" />
        <xs:element name="Element2" type="xs:string" />
      </xs:sequence>
       <xs:attribute name="Attribute1" type="xs:integer" use="optional" />
       <xs:attribute name="Attribute2" type="xs:boolean" use="required" />
     </xs:complexType>
  </xs:element>

Następnie możesz po prostu zbudować XML w następujący sposób:

RootElement rootElement = new RootElement;
rootElement.Element1 = "Element1";
rootElement.Element2 = "Element2";
rootElement.Attribute1 = 5;
rootElement.Attribute2 = true;

Lub po prostu załaduj XML z pliku w ten sposób:

RootElement rootElement = RootElement.Load(filePath);

Lub zapisz to w ten sposób:

rootElement.Save(string);
rootElement.Save(textWriter);
rootElement.Save(xmlWriter);

rootElement.Untyped zwraca również element w postaci XElement (od LINQ do XML).

65199
źródło
wygląda na to, że ten kod nie działa. kiedy chcę to zrobić, nie stosuje się RootElement
żadnej zapisanej funkcji
24
new XElement("Foo",
       from s in nameValuePairList
       select
             new XElement("Bar",
                  new XAttribute("SomeAttr", "SomeAttrValue"),
                          new XElement("Name", s.Name),
                          new XElement("Value", s.Value)
                         )
            );
Vincent
źródło
10

XmlWriter to najszybszy sposób na napisanie dobrego XML. XDocument, XMLDocument i niektóre inne działają również dobrze, ale nie są zoptymalizowane do pisania XML. Jeśli chcesz napisać XML tak szybko, jak to możliwe, zdecydowanie powinieneś użyć XmlWriter.

Mikael Söderström
źródło
6
To znaczy, jeśli chcesz, aby komputer zapisał XML tak szybko, jak to możliwe. Jeśli Ty, programista, chcesz stworzyć XML w najprostszy i najbardziej naturalny sposób, XmlWriter prawdopodobnie nie jest rozwiązaniem!
sjy
4

Myślę, że ten zasób powinien wystarczyć do umiarkowanego zapisu / załadowania XML: odczyt / zapis XML przy użyciu C # .

Moim zadaniem było przechowywanie notacji muzycznej. Wybieram XML, ponieważ, jak sądzę, .NET jest wystarczająco dojrzały, aby umożliwić łatwe rozwiązanie zadania. Miałem rację :)

Oto prototyp mojego pliku piosenki:

<music judul="Kupu-Kupu yang Lucu" pengarang="Ibu Sud" tempo="120" birama="4/4" nadadasar="1=F" biramapembilang="4" biramapenyebut="4">
    <not angka="1" oktaf="0" naikturun="" nilai="1"/>
    <not angka="2" oktaf="0" naikturun="" nilai="0.5"/>
    <not angka="5" oktaf="1" naikturun="/" nilai="0.25"/>
    <not angka="2" oktaf="0" naikturun="\" nilai="0.125"/>
    <not angka="1" oktaf="0" naikturun="" nilai="0.0625"/>
</music>

Można to rozwiązać dość łatwo:

Aby zapisać do pliku:

 private void saveToolStripMenuItem_Click(object sender, EventArgs e)
 {
     saveFileDialog1.Title = "Save Song File";
     saveFileDialog1.Filter = "Song Files|*.xsong";
     if (saveFileDialog1.ShowDialog() == DialogResult.OK)
     {
         FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.Create);
         XmlTextWriter w = new XmlTextWriter(fs, Encoding.UTF8);
         w.WriteStartDocument();
         w.WriteStartElement("music");
         w.WriteAttributeString("judul", Program.music.getTitle());
         w.WriteAttributeString("pengarang", Program.music.getAuthor());
         w.WriteAttributeString("tempo", Program.music.getTempo()+"");
         w.WriteAttributeString("birama", Program.music.getBirama());
         w.WriteAttributeString("nadadasar", Program.music.getNadaDasar());
         w.WriteAttributeString("biramapembilang", Program.music.getBiramaPembilang()+"");
         w.WriteAttributeString("biramapenyebut", Program.music.getBiramaPenyebut()+"");

         for (int i = 0; i < listNotasi.Count; i++)
         {
             CNot not = listNotasi[i];
             w.WriteStartElement("not");
             w.WriteAttributeString("angka", not.getNot() + "");
             w.WriteAttributeString("oktaf", not.getOktaf() + "");
             String naikturun="";
             if(not.isTurunSetengah())naikturun="\\";
             else if(not.isNaikSetengah())naikturun="/";
             w.WriteAttributeString("naikturun",naikturun);
             w.WriteAttributeString("nilai", not.getNilaiNot()+"");
             w.WriteEndElement();
         }
         w.WriteEndElement();

         w.Flush();
         fs.Close();
     }

 }

Aby załadować plik:

openFileDialog1.Title = "Open Song File";
openFileDialog1.Filter = "Song Files|*.xsong";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
    FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open);
    XmlTextReader r = new XmlTextReader(fs);

    while (r.Read())
    {
        if (r.NodeType == XmlNodeType.Element)
        {
            if (r.Name.ToLower().Equals("music"))
            {
                Program.music = new CMusic(r.GetAttribute("judul"),
                    r.GetAttribute("pengarang"),
                    r.GetAttribute("birama"),
                    Convert.ToInt32(r.GetAttribute("tempo")),
                    r.GetAttribute("nadadasar"),
                    Convert.ToInt32(r.GetAttribute("biramapembilang")),
                    Convert.ToInt32(r.GetAttribute("biramapenyebut")));
            }
            else
                if (r.Name.ToLower().Equals("not"))
                {
                    CNot not = new CNot(Convert.ToInt32(r.GetAttribute("angka")), Convert.ToInt32(r.GetAttribute("oktaf")));
                    if (r.GetAttribute("naikturun").Equals("/"))
                    {
                        not.setNaikSetengah();
                    }
                    else if (r.GetAttribute("naikturun").Equals("\\"))
                    {
                        not.setTurunSetengah();
                    }
                    not.setNilaiNot(Convert.ToSingle(r.GetAttribute("nilai")));
                    listNotasi.Add(not);
                }
        }
        else
            if (r.NodeType == XmlNodeType.Text)
            {
                Console.WriteLine("\tVALUE: " + r.Value);
            }
    }
}

}
}
swdev
źródło
1

Dla prostych rzeczy, po prostu używam klas XmlDocument / XmlNode / XmlAttribute i XmlDocument DOM znalezionych w System.XML.

Generuje dla mnie XML, muszę tylko połączyć kilka elementów razem.

Jednak w większych sprawach używam serializacji XML.

FlySwat
źródło
1

W prostych przypadkach sugerowałbym także spojrzenie na XmlOutput, płynny interfejs do budowania Xml.

XmlOutput doskonale nadaje się do prostego tworzenia Xml z czytelnym i łatwym do utrzymania kodem, jednocześnie generując prawidłowy Xml. Orginal poczta ma kilka świetnych przykładów.

Todd
źródło
-3

Jak powyżej.

Używam stringbuilder.append ().

Bardzo proste, a następnie możesz wykonać xmldocument.load (obiekt strinbuilder jako parametr).

Prawdopodobnie znajdziesz się w pliku string.concat w parametrze append, ale jest to bardzo proste podejście.

GurdeepS
źródło
11
Z wyjątkiem sytuacji, gdy zapomnisz poprawnie zakodować coś i napiszesz nielegalny Xml.
Robert Paulson,
3
Ta odpowiedź została całkowicie odrzucona, ale w oparciu o to pytanie rzuciłem okiem na jedną z moich własnych implementacji, w której buduję XML. W moim konkretnym projekcie konsekwentnie stwierdziłem, że budowanie za pomocą StringBuilder skutkuje czasem przetwarzania o 10% szybszym niż przy użyciu XDocument / XmlWriter. Ale czuję się komfortowo z XML-em i to dotyczy mojego konkretnego projektu. (Dla porównania, końcowe rozmiary XML to około 3,4 MB, z ponad 8000 linii.)
James Skemp
2
Byłbym ciekawy, czy zmierzyłeś kompromis między wydajnością aplikacji (czy mówimy tutaj o milisekundach ulepszeń?) A konserwacją aplikacji (czy Twoi inżynierowie muszą zapoznać się z kodem przez godzinę przed wprowadzeniem zmian?)
Dan Esparza