【问题标题】:Programmatically format XML in indented form just like Visual Studio's auto-format就像 Visual Studio 的自动格式化一样,以缩进形式以编程方式格式化 XML
【发布时间】:2010-11-22 20:17:43
【问题描述】:

我还没有找到一种方法,使用 .NET 的 XmlWriter 和关联的 XmlWriterSettings 来格式化缩进形式的 XML 字符串,这与 Visual Studio 使用其自动格式化命令(Ctrl-E Ctrl-D,或者,取决于关于键盘映射,Ctrl-K Ctrl-D)。

我想这样做是因为我习惯性地在 VS 中自动格式化所有文件,包括代码和 .config 文件。我有一个更新 .config 文件的安装程序应用程序,我希望查看实际差异而不是更改整个文档。

我还没有探索自动格式化的所有不同格式选项,但我喜欢每个 XML 属性位于单独的行,第一个属性与开始标记在同一行,后续的与第一个对齐,像这样:

<asset assetId="12345"
       bucket="default"
       owner="nobody">
  <file path="\\localhost\share\assetA.mov"/>
  <metadata metadataId="23456"
            key="asset_type"
            value="video"/>
</asset>

我尝试使用 XmlWriterSettings 属性“NewLineHandling = NewLineHandling.None”和“NewLineOnAttributes = true”进行格式化,但这会将第一个属性放在开始标记下方,并且所有属性都具有相同的缩进,而不管元素名称,如下所示:

<asset
  assetId="12345"
  bucket="default"
  owner="nobody">
  <file
    path="\\localhost\share\assetA.mov" />
  <metadata metadataId="23456"
    key="asset_type"
    value="video" />
</asset>

请注意,标准 XmlWriter 还以“ />”(斜杠前的额外空格)结束仅属性元素,我不喜欢这但不确定这是否是 XML 标准。我认为 Visual Studio 使用开发人员随时可用的相同 API 选项,但我还没有找到那些神奇的设置。无论如何,这是我的格式化方法:

public static string FormatXml( string xmlString, bool indented )
{
    using ( TextReader textReader = new StringReader( xmlString ) )
    using ( XmlReader xmlReader = new XmlTextReader( textReader ) )
    {
        using ( TextWriter textWriter = new StringWriter() )
        {
            var settings = new XmlWriterSettings();
            if ( indented )
            {
               settings.Indent = true;
               settings.IndentChars = "  ";
               settings.NewLineOnAttributes = true;
               settings.NewLineHandling = NewLineHandling.None;
            }
            using ( var xmlWriter = XmlWriter.Create( textWriter, settings ) )
            {
                while ( xmlReader.Read() )
                    xmlWriter.WriteNode( xmlReader, false );
            }
            return textWriter.ToString();
        }
    }
}

【问题讨论】:

    标签: .net xml visual-studio formatting autoformatting


    【解决方案1】:

    我误解了这个问题。实际上我不知道是否有办法按照您显示的方式对齐属性。您可以尝试自己实现它,如下所示:

        public static string FormatXml(string xmlString, bool indented)
        {
            using (TextReader textReader = new StringReader(xmlString))
            using (XmlReader xmlReader = new XmlTextReader(textReader))
            {
                using (TextWriter textWriter = new StringWriter())
                {
                    string indent = "";
                    string attributeIndent = "";
    
                    while (xmlReader.Read())
                    {
                        if (xmlReader.NodeType == XmlNodeType.Element)
                        {
                            attributeIndent = "";
                            string element = xmlReader.Name;
                            textWriter.Write("{0}<{1}", indent, element);
    
                            if (!xmlReader.HasAttributes)
                                textWriter.WriteLine(">");
                            else
                            {
                                int actual = 1;
                                while (xmlReader.MoveToNextAttribute())
                                {
                                    string content = String.Format("{0} {1}={2}", attributeIndent, xmlReader.Name, xmlReader.Value);
                                    if (actual != xmlReader.AttributeCount)
                                        textWriter.WriteLine(content);
                                    else
                                        textWriter.Write(content);
    
                                    if (string.IsNullOrEmpty(attributeIndent))
                                        attributeIndent = indent + Enumerable.Repeat<string>(" ", element.Length + 1).Aggregate((a, b) => a + b);
    
                                    actual++;
                                }
                                xmlReader.MoveToElement();
                                textWriter.WriteLine(">");
                                attributeIndent = "";
                            }
                            if (!xmlReader.IsEmptyElement)
                            {
                                indent += "  ";
                                textWriter.WriteLine(">");
                            }
                            else
                                textWriter.WriteLine("/>");
                        }
                        else if (xmlReader.NodeType == XmlNodeType.EndElement)
                        {
                            indent = indent.Substring(0, indent.Length - 2);
                            textWriter.WriteLine("{0}</{1}>", indent, xmlReader.Name);
                        }
                        else if (xmlReader.NodeType == XmlNodeType.Text)
                        {
                            textWriter.WriteLine(xmlReader.Value);
                        }
                    }
    
                    return textWriter.ToString();
                }
            }
        }
    

    【讨论】:

    • 感谢您的示例。我还没有尝试过,但我知道我总是可以手动输出元素并且必须处理不同的节点类型,但我希望微软不会隐藏他们的 Visual Studio 实现。
    • 嗯,其实我也不知道有没有;谷歌搜索我什么也没找到。我希望我发布的内容可以帮助到你。
    【解决方案2】:

    我认为引号是无效的 xml,这可能会给读者/作者带来一些胃痛。除此之外,您为什么不直接告诉您的差异应用程序忽略空格?

    【讨论】:

    • 在大多数差异应用程序中,“忽略空格”不会跨越多行。
    猜你喜欢
    • 2022-08-10
    • 1970-01-01
    • 2016-04-18
    • 2011-05-17
    • 2011-07-11
    • 1970-01-01
    • 2017-02-06
    • 1970-01-01
    • 2015-04-20
    相关资源
    最近更新 更多