2017-06-23 2 views
3

Mein Ziel ist es, eine geänderte XML-Datei auszugeben und eine spezielle Einrückung beizubehalten, die in der ursprünglichen Datei vorhanden war. Das Ziel ist, dass die resultierende Datei immer noch wie das Original aussieht, wodurch sie einfacher zu vergleichen und durch die Quellcodeverwaltung zusammenzuführen sind.So verwenden Sie XDocument.Save zum Speichern einer Datei mit benutzerdefinierten Einzug für Attribute

Mein Programm wird eine XML-Datei lesen und ein bestimmtes Attribut hinzufügen oder ändern.

<Base Import="..\commom\style.xml"> 
    <Item Width="480" 
     Height="500" 
     VAlign="Center" 
     Style="level1header"> 
(...) 

In diesem Fall möchte ich einfach alle Attribute über den ersten mit dem ersten auszurichten:

Hier ist die Formatierung ich versuche zu erreichen/bewahren.

XmlWriterSettings bietet Formatierungsoptionen, aber sie werden nicht das Ergebnis erreichen, das ich suche.

settings.Indent = true; 
settings.NewLineOnAttributes = true; 

Diese Einstellungen werden das erste Attribut auf einem Neue-Zeile setzen, anstatt sie auf der gleichen Linie wie die Knoten zu halten, und Attribute, die mit dem Knoten in einer Reihe aufstellen wird. Hier

ist der Load Aufruf, die Leerzeichen zu erhalten, fragt:

MyXml = XDocument.Load(filepath, LoadOptions.PreserveWhitespace); 

Aber es scheint, als ob es nicht tun, was ich erwartet hatte.

Ich habe versucht, eine benutzerdefinierte Klasse bereitzustellen, die von XmlWriter auf den XDocument.Save Aufruf abgeleitet ist, aber ich habe es nicht geschafft, Leerräume korrekt einzufügen, ohne in InvalidOperationException zu laufen. Außerdem scheint diese Lösung für den kleinen Zusatz, den ich suche, übertrieben zu sein.

Als Referenz ist mein speichern nennen, nicht meine benutzerdefinierte XML-Writer (die ohnehin nicht funktioniert)

XmlWriterSettings settings = new XmlWriterSettings(); 
settings.Indent = true; 
settings.NewLineOnAttributes = true; 
settings.OmitXmlDeclaration = true; 
using (XmlWriter writer = XmlWriter.Create(filepath + "_auto", settings)) 
{ 
    MyXml.Save(writer); 
} 
+4

Ich glaube nicht System.XML entworfen wurde völlig willkürlich Formatierung Spezifikationen zu unterstützen. Sie könnten Ihre eigene XmlWriter-Implementierung schreiben, die Ihr spezifisches Format unterstützt, oder einfach ein Format verwenden, das von Anfang an unterstützt wird. –

Antwort

0

ich nicht XDocument.Save zusammen mit endete, und erstellt stattdessen eine Klasse, die Nimmt das XDocument, einen XmlWriter, sowie einen TextWriter. Die Klasse analysiert alle Knoten in XDocument, TextWriter ist an die Datei auf der Festplatte gebunden, die XmlWriter als Ausgabe-Pipe verwendet.

Meine Klasse verwendet dann den XmlWriter, um XML auszugeben. Um den zusätzlichen Abstand zu erreichen, habe ich die hier beschriebene Lösung https://stackoverflow.com/a/24010544/5920497 verwendet, weshalb ich auch den zugrundeliegenden TextWriter verwende.

Hier ist ein Beispiel für die Lösung.

die Klasse aufrufen, das Dokument zu speichern:

XmlWriterSettings settings = new XmlWriterSettings(); 
settings.Indent = true; 
settings.NewLineOnAttributes = false; // Behavior changed in PrettyXmlWriter 
settings.OmitXmlDeclaration = true; 

using(TextWriter rawwriter = File.CreateText(filepath)) 
using (XmlWriter writer = XmlWriter.Create(rawwriter, settings)) 
{ 
    // rawwriter is used both by XmlWriter and PrettyXmlWriter 
    PrettyXmlWriter outputter = new PrettyXmlWriter(writer, rawwriter); 
    outputter.Write(MyXml); 

    writer.Flush(); 
    writer.Close(); 
} 

Innen PrettyXmlWriter:

private XmlWriter Writer { get; set; } 
private TextWriter InnerTextWriter { get; set; } 

public void Write(XDocument doc) 
{ 
    XElement root = doc.Root; 
    WriteNode(root, 0); 
} 

private void WriteNode(XNode node, int currentNodeDepth) 
{ 
    if(node.NodeType == XmlNodeType.Element) 
    { 
     WriteElement((XElement)node, currentNodeDepth); 
    } 
    else if(node.NodeType == XmlNodeType.Text) 
    { 
     WriteTextNode((XText)node, currentNodeDepth, doIndentAttributes); 
    } 
} 

private void WriteElement(XElement node, int currentNodeDepth) 
{ 
    Writer.WriteStartElement(node.Name.LocalName); 

    // Write attributes with indentation 
    XAttribute[] attributes = node.Attributes().ToArray(); 

    if(attributes.Length > 0) 
    { 
     // First attribute, unindented. 
     Writer.WriteAttributeString(attributes[0].Name.LocalName, attributes[0].Value); 

     for(int i=1; i<attributes.Length; ++i) 
     { 
      // Write indentation 
      Writer.Flush(); 
      string indentation = Writer.Settings.NewLineChars + string.Concat(Enumerable.Repeat(Writer.Settings.IndentChars, currentNodeDepth)); 
      indentation += string.Concat(Enumerable.Repeat(" ", node.Name.LocalName.Length + 1)); 
      // Using Underlying TextWriter trick to output whitespace 
      InnerTextWriter.Write(indentation); 

      Writer.WriteAttributeString(attributes[i].Name.LocalName, attributes[i].Value); 
     } 
    } 

    // output children 
    foreach(XNode child in node.Nodes()) 
    { 
     WriteNode(child, currentNodeDepth + 1); 
    } 

    Writer.WriteEndElement(); 
} 
Verwandte Themen