2009-08-17 3 views
2

나는 .NET에서 일부 .vcrpoj 파일을 수정하고있어하지만 난 그들에게 (내 사랑하는 도구를 사용하여 파괴를 난파) 서식 변경 내용을 저장할 때 원본 파일은 다음과 같이 :새 노드에서 닫는 노드와 태그를 사용하여 XML을 포맷하는 방법은 무엇입니까?

<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; 

을 사용하고 t을 정의하는 방법이 있나요 그는 Visual Studio에서 사용하는 형식과 일치하도록 설정합니까? (그렇지 않으면 NewLineOnAttributes가 필요합니다.

답변

6

기본 제공 XmlWriter 구현을 사용하여 구현할 수 있다고 생각하지 않습니다 ... XmlTextWriter에서 상속받을 수 있고 적절한 방법을 재정 의하여 (어떤 코드인지 확실하지 않음) 요소를 여기


몇 XML 인식은 diff 도구 형식으로 원하는 (즉, 서식을 무시하는 의미에 따라 파일을 비교합니다) :

으로 이러한 도구를 사용하면 생성하는 XML 형식에 대해 걱정할 필요가 없습니다.

+0

좀 더 구체적으로 기재 할 수 있습니까? 'XmlWriter'를 상속 할 때'base '를 어떻게 만들지는 모르겠다. (내장 된 구현체로 작업 할 때 정적'.Create' 메소드를 사용하지만 이것을'base'에 어떻게 전달 하는가?). – Motti

+0

XmlWriter 생성자는 보호되어 있으므로 파생 클래스에서 호출 할 수 있습니다. 그러나 XmlTextWriter에서 직접 상속하는 것이 더 쉬울 것이므로 처음부터 모든 코드를 작성할 필요가 없습니다. –

+2

시도해 보았습니다. 많은 코드 없이는 그렇게 할 수없는 것 같습니다 ... 어쨌든 포맷팅과 관련된 유일한 문제가 diff 도구 인 경우 XML을 이해하는 도구를 사용하고 텍스트뿐만 아니라 의미를 비교하는 것이 좋습니다. Beyond Compare를 사용하는 경우에는 비교하기 전에 Tidy로 두 문서의 서식을 지정하는 플러그인이 있습니다. –

2

중요합니까? 아마도 .NET IDE는 표준 XML을 읽습니다. 그 모든 것이 XML이 합법적이라고 인정하는 것입니다. 정말 문제가 있습니까?

EDIT : (다른 사용자는 실제 문제가 diff'ing으로 나타남). 새로운 결과를 생성하기 위해 사용하고있는 프로세스를 호출 해 봅시다. 이전 파일이 F 인 이전 결과 파일 P를 실행하면 간단히 F를 읽고 변경없이 다시 작성하면됩니다. 원본 파일의 새로운 (불편한) 형식.

나는 당신이, 엡실론 변화 을 원래의 F를 수정하고이 생산되는 곳은, 가 P에게 (F의 + 엡실론)를 실행하고있는 것 같은데요, 다음 어려움 원본과 새로운 비교가 . 이 문제를 해결하는 한 가지 방법은 간단히 원본을 P (F)로 실행하고 P (F + 엡실론)과 비교하는 것입니다. 아마도 두 형식의 서식 스타일이 같고 차이가 적절할 것입니다. 이러한 스턴트를 "정규화"라고합니다.

다른 대안은 XML을 이해하는 diff 도구를 실행하여 이며 어떤 형식이 부적절한 것인지 알 수 있습니다.

+0

질문을 다시 읽습니다. "서식을 변경하면 (** 내 diff 도구로 난파 된 **)" –

+0

+1 XML 인식 diff 도구 –

1

또한 WinMerge를 (무료, GPL), 다른 모든 분명히 잘 실행으로 어쩌면, 문제를 해결할 당신은 diff 도구를 변경 XML 플러그인

1

와. WinMerge과 같은 일부 diff 도구에는 무시할 차이점을 필터링 할 수있는 옵션이 있습니다. 규칙을 정의하는 정규 표현식을 제공 할 수도 있습니다.

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) 
       ); 
     } 
    } 
0

많은 파일을 수정하는 것처럼 들리므로 실용적이지는 않지만 VS에서 파일을 열고 저장하면 표준 형식이 복원됩니다.

1

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와 같은 시스템을 사용하여 도구를 통해 변경 사항을 자동 병합하는 경우 변경 사항을 가능한 한 원자 적으로 유지하는 것이 가장 좋습니다.

예 : 마지막 속성이 한 사람에 의해 변경되고 추가 속성이 다른 사람에 의해 끝에 추가되는 경우 어떤 행에 닫는 것이 포함되어야하는지에 따라 인공 충돌을 만들 이유가 없습니다 > (또는 />)를 누르십시오. 이 시나리오의 가장 좋은 해결책은 닫는 괄호가 자체 줄에 있고 충돌을 모두 피하는 것입니다.

관련 문제