2017-06-23 13 views
3

私の目標は、変更されたXMLファイルを出力し、元のファイルにあった特殊なインデントを保持することです。目的は、結果のファイルが元のように見えるようにすることで、ソースコントロールを使ってファイルを比較して簡単にマージすることです。XDocument.Saveを使用して属性のカスタムインデントを使用してファイルを保存する方法

私のプログラムはXMLファイルを読み込み、特定の属性を追加または変更します。ここで

は私が守る/達成しようとしているフォーマットである。この場合、

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

、私は単純に最初のものとの最初の1を超えてすべての属性を揃えたいです。

XmlWriterSettingsはフォーマットオプションを提供しますが、私が探している結果は得られません。

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

これらの設定は、代わりにノードと同じ行にそれを維持する、改行に最初の属性を置く、およびノー​​ドと属性をラインアップします。ここで

は空白を保持するよう要求Load呼び出し、次のとおりです。

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

しかし、それは私が期待したもの行うことはありませんように思えます。

私はXDocument.SaveコールにXmlWriterから派生したカスタムクラスを提供しようとしたが、私はInvalidOperationExceptionに実行せずに空白を正しく挿入するために管理していません。加えて、私が探している小さな追加のために、その解決策は残酷に思われます。参考のために、これは私が完全にXDocument.Saveを使用していないことになった、と代わりにそのクラスを作成した(とにかく動作しません)私のカスタムXMLライター

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

私は、System.Xmlのは、完全に任意のフォーマットの仕様をサポートするように設計されたとは思いません。特定の形式をサポートする独自のXmlWriter実装を作成することもできますし、そのまま使用できる形式を使用して開始することもできます。 –

答えて

0

を使用していない、私の保存を

を呼び出していますXDocument、XmlWriter、およびTextWriterを取ります。 クラスはXDocument内のすべてのノードを解析しますが、TextWriterはXmlWriterが出力パイプとして使用するディスク上のファイルにバインドされています。

My classは、XmlWriterを使用してxmlを出力します。余分なスペーシングを実現するために、私はここで説明した解決策、https://stackoverflow.com/a/24010544/5920497を使用しました。そのため、基本となるTextWriterも使用しています。

解決策の例を次に示します。文書を保存するために、クラスを呼び出す

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(); 
} 

インサイド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(); 
}