将XML字符串注入XmlWriter时的XML缩进

时间:2009-05-13 15:24:51

标签: c# .net xml

我有一个XmlTextWriter使用该文本编写器写入文件和XmlWriter。此文本编写器设置为输出制表符缩进的XML:

XmlTextWriter xtw = new XmlTextWriter("foo.xml", Encoding.UTF8);
xtw.Formatting = Formatting.Indented;
xtw.IndentChar = '\t';
xtw.Indentation = 1;

XmlWriter xw = XmlWriter.Create(xtw);

根据Jeff的MSDN链接进行了更改:

XmlWriterSettings set = new XmlWriterSettings();
set.Indent = true;
set.IndentChars = "\t";
set.Encoding = Encoding.UTF8;

xw = XmlWriter.Create(f, set);

这不会改变最终结果。


现在我在我的XmlWriter中是一个任意深度,我从其他地方(我无法控制)得到一串XML,这是一个单行,非缩进的XML。如果我调用xw.WriteRaw(),那么该字符串是逐字注入的,并不遵循我想要的缩进。

...
string xml = ExternalMethod();
xw.WriteRaw(xml);
...

基本上,我想要一个解析XML字符串并遍历所有WriteStartElement等的WriteRaw,以便根据XmlTextWriter的设置重新格式化。

我的偏好是使用我已经拥有的设置执行此操作的方法,并且无需重新加载最终XML以重新格式化它。我也不想用XmlReader等解析XML字符串,然后模仿它在我的XmlWriter中找到的东西(非常非常手动的过程)。

在最后,我宁愿有一个简单的解决方案,而不是遵循我的偏好。 (当然,最好的解决方案很简单并且符合我的偏好。)

6 个答案:

答案 0 :(得分:30)

如何使用XmlReader将xml读取为xml节点?

string xml = ExternalMethod();
XmlReader reader =  XmlReader.Create(new StringReader(xml));
xw.WriteNode(reader, true);

答案 1 :(得分:3)

您不应该使用XmlTextWriter,如MSDN所示:

  

在.NET Framework 2.0版中   发布,建议的做法是   使用创建XmlWriter实例   XmlWriter.Create方法和   XmlWriterSettings类。这允许   你要充分利用所有的优势   这里介绍的新功能   发布。有关更多信息,请参阅   创建XML Writer。

相反,您应该使用XmlWriter.Create来获取作家。然后,您可以使用XmlWriterSettings类来指定缩进等内容。

XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = "\t";

更新

我认为你可以使用WriteNode。您获取xml字符串并将其加载到XDocument或XmlReader中,然后使用该节点将其写入XmlWriter。

答案 2 :(得分:2)

这是迄今为止我所获得的最好成绩。一个非常手动的过程,只支持所写的内容。我的字符串XML只不过是标签,属性和文本数据。如果它支持名称空间,CDATA等,那么这必须相应增长。

非常手动,非常混乱,很可能容易出错,但它确实完成了我的偏好。

private static void PipeXMLIntoWriter(XmlWriter xw, string xml)
{
    byte[] dat = new System.Text.UTF8Encoding().GetBytes(xml);
    MemoryStream m = new MemoryStream();
    m.Write(dat, 0, dat.Length);
    m.Seek(0, SeekOrigin.Begin);
    XmlReader r = XmlReader.Create(m);

    while (r.Read())
    {
        switch (r.NodeType)
        {
            case XmlNodeType.Element:
                xw.WriteStartElement(r.Name);

                if (r.HasAttributes)
                {
                    for (int i = 0; i < r.AttributeCount; i++)
                    {
                        r.MoveToAttribute(i);
                        xw.WriteAttributeString(r.Name, r.Value);
                    }
                }

                if (r.IsEmptyElement)
                {
                    xw.WriteEndElement();
                }
                break;
            case XmlNodeType.EndElement:
                xw.WriteEndElement();
                break;
            case XmlNodeType.Text:
                xw.WriteString(r.Value);
                break;

            default:
                throw new Exception("Unrecognized node type: " + r.NodeType);
        }
    }
}

答案 3 :(得分:2)

撰写上述答案我发现这有效:

private static string FormatXML(string unformattedXml) {
    // first read the xml ignoring whitespace
    XmlReaderSettings readeroptions= new XmlReaderSettings {IgnoreWhitespace = true};
    XmlReader reader = XmlReader.Create(new StringReader(unformattedXml),readeroptions);

    // then write it out with indentation
    StringBuilder sb = new StringBuilder();
    XmlWriterSettings xmlSettingsWithIndentation = new XmlWriterSettings { Indent = true};                       
    using (XmlWriter writer = XmlWriter.Create(sb, xmlSettingsWithIndentation)) {
        writer.WriteNode(reader, true);
    }

    return sb.ToString();
}

答案 4 :(得分:1)

我正在寻找这个问题的答案,但是在VB.net中。

感谢Colin Burnett,我解决了它。我做了两处更正:首先,XmlReader必须忽略空格(settings.IgnoreWhiteSpaces);第二,读者必须在读取属性后返回元素。您可以在下面看到代码的外观。

此外,我尝试了GreyCloud的解决方案,但在生成的XML中有一些恼人的空白属性(xlmns)。

Private Sub PipeXMLIntoWriter(xw As XmlWriter, xml As String)
    Dim dat As Byte() = New System.Text.UTF8Encoding().GetBytes(xml)
    Dim m As New MemoryStream()
    m.Write(dat, 0, dat.Length)
    m.Seek(0, SeekOrigin.Begin)
    Dim settings As New XmlReaderSettings
    settings.IgnoreWhitespace = True
    settings.IgnoreComments = True
    Dim r As XmlReader = XmlReader.Create(m, settings)

    While r.Read()
          Select Case r.NodeType
                Case XmlNodeType.Element
                    xw.WriteStartElement(r.Name)

                    If r.HasAttributes Then
                        For i As Integer = 0 To r.AttributeCount - 1
                            r.MoveToAttribute(i)
                            xw.WriteAttributeString(r.Name, r.Value)
                        Next
                        r.MoveToElement()
                    End If

                    If r.IsEmptyElement Then
                        xw.WriteEndElement()
                    End If
                    Exit Select
                Case XmlNodeType.EndElement
                    xw.WriteEndElement()
                    Exit Select
                Case XmlNodeType.Text
                    xw.WriteString(r.Value)
                    Exit Select
                Case Else

                    Throw New Exception("Unrecognized node type: " + r.NodeType)
            End Select
      End While
End Sub

答案 5 :(得分:0)

怎么样:

string xml = ExternalMethod();
var xd = XDocument.Parse(xml);
xd.WriteTo(xw);