XmlWriter.Create는 XmlWellFormedWriter에 래핑 된 특정 XmlRawWriter를 반환하며이 모든 XmlWellWriter는 내부로 정의되므로 확장 할 수 없습니다.
그러나 XmlTextWriter를 확장 할 수는 있지만 제대로 구성된 작성기와 비교할 때 매우 제한된 기능 집합을 가지고 있습니다.
그래서 ... 여기
내가 잘 형성 작가에서 누락 된 기능 및 excepts의 XmlWriterSettings의 대부분이이 문제에 대처하기 위해 만든 사용자 지정하여 XmlTextWriter입니다 :
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);
}
그것은 좋은 것입니다이 기능은 단지 잘 형성 WR에 추가 된 경우 XmlWriterSettings에서 옵션으로 반복하십시오.
때로는 diff 도구를 변경하는 것이 옵션이 아닙니다 (또는 처음부터 문제가 있습니다) perforce와 같은 시스템을 사용하여 도구를 통해 변경 사항을 자동 병합하는 경우 변경 사항을 가능한 한 원자 적으로 유지하는 것이 가장 좋습니다.
예 : 마지막 속성이 한 사람에 의해 변경되고 추가 속성이 다른 사람에 의해 끝에 추가되는 경우 어떤 행에 닫는 것이 포함되어야하는지에 따라 인공 충돌을 만들 이유가 없습니다 > (또는 />)를 누르십시오. 이 시나리오의 가장 좋은 해결책은 닫는 괄호가 자체 줄에 있고 충돌을 모두 피하는 것입니다.
좀 더 구체적으로 기재 할 수 있습니까? 'XmlWriter'를 상속 할 때'base '를 어떻게 만들지는 모르겠다. (내장 된 구현체로 작업 할 때 정적'.Create' 메소드를 사용하지만 이것을'base'에 어떻게 전달 하는가?). – Motti
XmlWriter 생성자는 보호되어 있으므로 파생 클래스에서 호출 할 수 있습니다. 그러나 XmlTextWriter에서 직접 상속하는 것이 더 쉬울 것이므로 처음부터 모든 코드를 작성할 필요가 없습니다. –
시도해 보았습니다. 많은 코드 없이는 그렇게 할 수없는 것 같습니다 ... 어쨌든 포맷팅과 관련된 유일한 문제가 diff 도구 인 경우 XML을 이해하는 도구를 사용하고 텍스트뿐만 아니라 의미를 비교하는 것이 좋습니다. Beyond Compare를 사용하는 경우에는 비교하기 전에 Tidy로 두 문서의 서식을 지정하는 플러그인이 있습니다. –