我正在修改.NET中的一些.vcrpoj
文件但是当我保存它们格式化更改(这会破坏我的diff工具)时,原始文件看起来像这样:
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
但是当我保存更改时,它看起来像这样:
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00">
<Platforms>
<Platform
Name="Win32" />
</Platforms>
<ToolFiles></ToolFiles>
我正在使用以下XmlWritterSettings
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = ("\t");
settings.Encoding = Encoding.UTF8;
settings.NewLineOnAttributes = true;
有没有办法定义设置以匹配visual studio使用的格式? (我需要NewLineOnAttributes
否则会更糟糕。
答案 0 :(得分:6)
我不认为你可以使用内置的XmlWriter
实现来实现它...你可以从XmlTextWriter继承,并覆盖适当的方法(不确定它是哪一个......)来编写具有所需格式的元素
以下是一些支持XML的diff工具(将基于语义比较文件,忽略格式化):
使用这些工具,您无需担心生成的XML格式
答案 1 :(得分:2)
重要吗?据推测,.NET IDE会读取标准XML。 重要的是,您的XML是合法的,并且显然是合法的。 你真的有问题吗?
编辑:(另一位用户表示真正的问题在于差异化)。 让我们调用您正在使用的任何过程来产生新结果 P,旧文件为F.如果你运行P(F)就是这么简单 读取F并将其写回,不做任何更改,你会得到 您在原始文件上的新(不方便)格式。
我在猜你在做什么 正在运行P(F + epsilon),您正在使用epsilon更改修改原始F, 并产生这个,然后你很难比较新的 与原来的。解决这个问题的一种方法就是简单地说 在原稿上运行P(F),并将其与P(F + epsilon)进行比较。 现在大概两者的格式化样式是相同的 你的差异是合理的。这种特技叫做 “归一化”。
另一种选择是运行一个理解XML的diff工具, 因此知道什么格式是无关紧要的。
答案 2 :(得分:1)
还有WinMerge(免费,GPL),带有xml插件
答案 3 :(得分:1)
也许改变你的差异工具将解决你的问题,因为其他一切显然运行正常。某些差异工具(如WinMerge)可以选择过滤要忽略的差异,即使您可以提供正则表达式来定义规则
答案 4 :(得分:1)
首先将其保存回xml,使用下面方法的修改版本进行读取和重写,以注入换行符和制表符。为此,您可以使用rdr.Depth获取选项卡计数,并在调用WriteEndElement之前使用wtr.WriteRaw(“\ r \ n”+ + new String('\ t',tabCount))来编写非重要的白色空间。对不起,这是UNTESTED代码,但它尽可能接近我。
public void CopyXmlContentsToFile(XmlTextReader rdr, XmlTextWriter wtr)
{
try
{
rdr.WhitespaceHandling = WhitespaceHandling.Significant;
wtr.Formatting = Formatting.Indented;
CopyNodes(rdr, wtr);
}
finally
{
rdr.Close();
wtr.Close();
}
}
void CopyNodes(XmlReader rdr, XmlWriter wtr)
{
if (rdr.NodeType == XmlNodeType.Text || rdr.NodeType == XmlNodeType.SignificantWhitespace)
{
wtr.WriteString(rdr.Value);
}
else if (rdr.NodeType == XmlNodeType.Whitespace)
return;
else if (rdr.NodeType == XmlNodeType.Element)
{
string elemName = rdr.LocalName;
bool empty = rdr.IsEmptyElement;
wtr.WriteStartElement(elemName);
while (rdr.MoveToNextAttribute())
{
if (rdr.Prefix.Length == 0)
wtr.WriteAttributeString(rdr.LocalName, rdr.Value);
}
if (rdr.NodeType == XmlNodeType.Attribute)
rdr.MoveToElement();
if (!empty)
{
while (rdr.Read() && rdr.NodeType != XmlNodeType.EndElement)
CopyNodes(rdr, wtr);
}
if (!empty && wtr.WriteState != WriteState.Content)
wtr.WriteRaw("");
if (!empty)
{
//Here we can inject our custom formatting with WriteRaw():
wtr.WriteRaw(Environment.NewLine + new String('\t', rdr.Depth));
}
wtr.WriteEndElement();
}
else
{
throw new ApplicationException(
String.Format("Unexpected node type {0} at line {1}.", rdr.NodeType, ((XmlTextReader)rdr).LineNumber)
);
}
}
答案 5 :(得分:1)
XmlWriter.Create返回一个包含在XmlWellFormedWriter中的特定XmlRawWriter,所有这些都定义为内部,因此您无法扩展它们。
但是,您可以扩展XmlTextWriter,但与格式良好的编写器相比,它的功能集非常有限。
因此...
这是我用来处理这个问题的自定义XmlTextWriter,它具有良好形成的编写器中缺少的大部分功能,并且除了XmlWriterSettings之外:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace System.Xml
{
public class CustomXmlTextWriter : XmlTextWriter
{
internal class CustomStreamWriter : StreamWriter
{
public CustomStreamWriter(Stream stream, Encoding encoding) : base(stream) { }
// This prevents the XmlTextWriter from writing the extra space before attributes, and the short EndElement " />"
public bool DisableSpace { get; set; }
public override void Write(char value)
{
if (DisableSpace && value == ' ') return;
else base.Write(value);
}
public override void Write(string value)
{
if (DisableSpace && value == " /") base.Write('/');
else base.Write(value);
}
}
public CustomXmlTextWriter(string filename, XmlWriterSettings settings) : this(new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Read), settings) { }
public CustomXmlTextWriter(Stream stream, XmlWriterSettings settings) : this(new CustomStreamWriter(stream, settings.Encoding), settings) { }
internal CustomXmlTextWriter(CustomStreamWriter writer, XmlWriterSettings settings)
: base(writer)
{
m_Writer = writer;
m_Settings = settings;
if (m_Settings.OmitXmlDeclaration == false)
{
string encoding = (m_Writer.Encoding.CodePage == 1201) ? "UTF-16BE" : m_Writer.Encoding.WebName;
m_Writer.WriteLine("<?xml version=\"1.0\" encoding=\"{0}\"?>", encoding);
}
}
private bool m_HasAttributes = false;
private Stack<bool> m_HasAttributesStack = new Stack<bool>();
private CustomStreamWriter m_Writer;
private XmlWriterSettings m_Settings;
public override XmlWriterSettings Settings { get { return m_Settings; } }
public override void WriteStartElement(string prefix, string localName, string ns)
{
if (WriteState == WriteState.Element)
{
if (m_HasAttributes && Settings.NewLineOnAttributes) { WriteIndent(m_HasAttributesStack.Count); }
WriteRaw(""); // Trick the XmlTextWriter into closing the previous element, and updating the WriteState
m_Writer.DisableSpace = false;
}
int indentLevel = m_HasAttributesStack.Count;
if (indentLevel > 0)
{
WriteIndent(indentLevel);
}
m_HasAttributesStack.Push(m_HasAttributes);
m_HasAttributes = false;
base.WriteStartElement(prefix, localName, ns);
}
public override void WriteEndElement()
{
if (m_HasAttributes && Settings.NewLineOnAttributes)
{
WriteIndent(m_HasAttributesStack.Count - 1);
}
m_HasAttributes = m_HasAttributesStack.Pop();
base.WriteEndElement();
m_Writer.DisableSpace = false;
}
public override void WriteFullEndElement()
{
m_HasAttributes = m_HasAttributesStack.Pop();
WriteIndent(m_HasAttributesStack.Count);
base.WriteFullEndElement();
}
public override void WriteStartAttribute(string prefix, string localName, string ns)
{
if (Settings.NewLineOnAttributes)
{
WriteIndent(m_HasAttributesStack.Count);
m_Writer.DisableSpace = true;
}
m_HasAttributes = true;
base.WriteStartAttribute(prefix, localName, ns);
}
public override void WriteString(string text)
{
if (m_Settings.NewLineHandling == NewLineHandling.Replace)
{
text = Regex.Replace(text, @"\r\n?|\n", m_Settings.NewLineChars);
}
else if (m_Settings.NewLineHandling == NewLineHandling.Entitize)
{
text = Regex.Replace(text, @"\n|\r", m => String.Format("&#x{0:X};", (int)m.Value[0]));
}
base.WriteString(text);
}
private void WriteIndent(int indentLevel)
{
if (Settings.Indent == false) return;
m_Writer.Write(Settings.NewLineChars);
for (int i = 0; i < indentLevel; ++i)
{
m_Writer.Write(Settings.IndentChars);
}
}
}
}
只需在项目中创建一个包含上述代码的文件,然后像这样使用它:
// Create the XmlWriter Settings as you normally would
// *Note: You can change or omit these, they are just for an example of what I supported
XmlWriterSettings settings = new XmlWriterSettings()
{
Encoding = Encoding.UTF8,
//OmitXmlDeclaration = true,
Indent = true,
//IndentChars = " ",
IndentChars = "\t",
NewLineOnAttributes = true,
//NewLineHandling = NewLineHandling.Entitize,
//NewLineHandling = NewLineHandling.Replace,
//NewLineChars = @"\n",
};
// Replace XmlWriter.Create with new CustomXmlTextWriter
//using (XmlWriter writer = XmlWriter.Create(path, settings))
using (XmlWriter writer = new CustomXmlTextWriter(path, settings))
{
xml.WriteTo(writer);
}
如果将此功能作为XmlWriterSettings中的一个选项添加到格式良好的编写器中,那将是很好的。
有时候改变diff工具不是一个选择(甚至首先是问题) 当使用像perforce这样的系统通过工具自动合并更改时,最好将更改保持为原子。
例如...... 如果一个人更改了最后一个属性,并且另一个人将另一个属性添加到最后,则没有理由根据哪一行应包含结束&gt;创建人为冲突。 (或/&gt;)。 这种情况的最佳解决方案是,如果结束括号是独立的,并避免冲突。
答案 6 :(得分:0)
听起来你正在修改很多文件,所以这可能不实用,但在VS中打开文件并保存它应该恢复标准格式。