I haven't found a way using .NET's XmlWriter and associated XmlWriterSettings to format an XML string in indented form exactly the way that Visual Studio does it with its auto-format command (Ctrl-E Ctrl-D, or, depending on keyboard mapping, Ctrl-K Ctrl-D).
我没有找到一种方法使用.NET的XmlWriter和关联的XmlWriterSettings以缩进的形式格式化XML字符串,与Visual Studio使用自动格式命令(Ctrl-E Ctrl-D,或者,取决于键盘映射)的方式完全相同,Ctrl-K Ctrl-D)。
I would like to do this because I habitually auto-format all my files in VS, both code and .config files. I have an installer app that updates .config files, and I would like to see actual diffs instead of the entire document changed.
我想这样做是因为我习惯性地自动格式化VS中的所有文件,包括代码和.config文件。我有一个更新.config文件的安装程序应用程序,我希望看到实际的差异而不是整个文档的更改。
I haven't explored all the different formatting options for auto-format, but I like each XML attribute to be on a separate line, with the first on the same line as the opening tag and subsequent ones lined up with the first, like this:
我没有探索自动格式的所有不同格式化选项,但我喜欢每个XML属性都在一个单独的行上,第一行与开始标记位于同一行,后续排列第一行,如下所示:
<asset assetId="12345"
bucket="default"
owner="nobody">
<file path="\\localhost\share\assetA.mov"/>
<metadata metadataId="23456"
key="asset_type"
value="video"/>
</asset>
I've tried formatting with XmlWriterSettings properties 'NewLineHandling = NewLineHandling.None' and 'NewLineOnAttributes = true', but that puts the first attribute below the opening tag and all attributes have the same indentation regardless of the # of characters in the element name, like this:
我尝试使用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>
Notice that the standard XmlWriter also ends attribute-only elements with " />" (extra space before the slash), which I dislike but not sure if that's the XML standard. I would think that Visual Studio uses the same API options readily available to developers, but I've yet to find those magical settings. Anyway, here's my format method:
请注意,标准的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();
}
}
}
3 个解决方案
#1
1
I had misunderstood the question. Actually I don't know if there is a way to align the attributes in the way you shown. You could try to implement it yourself, something like this:
我误解了这个问题。实际上我不知道是否有办法以你显示的方式对齐属性。您可以尝试自己实现它,如下所示:
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();
}
}
}
#2
0
See the answer here: Is there a stylesheet or Windows commandline tool for controllable XML formatting, specifically putting attributes one-per-line?
请参阅此处的答案:是否有用于可控XML格式的样式表或Windows命令行工具,特别是将属性设置为每行一个?
It's close, but the primary difference at a glance is that the first attribute is on a new line, whereas in Visual Studio it stays on the same line as the element name.
它很接近,但主要区别在于第一个属性是在新行上,而在Visual Studio中它与元素名称保持在同一行。
#3
0
I think quotes are invalid xml, which may give the reader/writer some heartburn. Other than that, why don't you just tell your diff application to ignore whitespace?
我认为引用是无效的xml,这可能会给读者/作者一些胃灼热。除此之外,你为什么不告诉你的diff应用程序忽略空格?
#1
1
I had misunderstood the question. Actually I don't know if there is a way to align the attributes in the way you shown. You could try to implement it yourself, something like this:
我误解了这个问题。实际上我不知道是否有办法以你显示的方式对齐属性。您可以尝试自己实现它,如下所示:
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();
}
}
}
#2
0
See the answer here: Is there a stylesheet or Windows commandline tool for controllable XML formatting, specifically putting attributes one-per-line?
请参阅此处的答案:是否有用于可控XML格式的样式表或Windows命令行工具,特别是将属性设置为每行一个?
It's close, but the primary difference at a glance is that the first attribute is on a new line, whereas in Visual Studio it stays on the same line as the element name.
它很接近,但主要区别在于第一个属性是在新行上,而在Visual Studio中它与元素名称保持在同一行。
#3
0
I think quotes are invalid xml, which may give the reader/writer some heartburn. Other than that, why don't you just tell your diff application to ignore whitespace?
我认为引用是无效的xml,这可能会给读者/作者一些胃灼热。除此之外,你为什么不告诉你的diff应用程序忽略空格?