2

.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そうでなければ、さらに悪いことが必要です)。

4

7 に答える 7

6

組み込みの実装でそれを行うことはできないと思いますXmlWriter... XmlTextWriter から継承し、適切なメソッドをオーバーライドして (どれがどれかわからない...)、目的の形式で要素を書き込むことができます


以下に XML 対応の diff ツールをいくつか示します (フォーマットを無視して、セマンティクスに基づいてファイルを比較します)。

これらのツールがあれば、生成する XML 形式について心配する必要はありません。

于 2009-08-17T16:50:51.170 に答える
2

それは問題ですか?おそらく、.NET IDE は標準の XML を読み取ります。重要なのは、あなたの XML が正当であるということだけです。本当にお困りですか?

編集:(別のユーザーは、実際の問題は差分にあることを示しています)。新しい結果 P を生成するために使用しているプロセスを呼び出しましょう。古いファイルは F です。P(F) を実行すると、単に F を読み取って、何も変更せずに書き戻すと、新しい (不便な)形式を元のファイルに追加します。

あなたがしていることは、元の F をイプシロンの変更で変更し、これを作成している P(F+epsilon) を実行していると推測していますが、新しいものと元のものを比較するのは困難です。この問題を解決する 1 つの方法は、単純にオリジナルに対して P(F) を実行し、それを P(F+ε) と比較することです。おそらく、両方の書式設定スタイルは同一であり、差分は合理的です。この種のスタントは「ノーマライゼーション」と呼ばれます。

もう 1 つの方法は、XML を理解する diff ツールを実行することです。したがって、どのフォーマットが無関係であるかを認識します。

于 2009-09-01T08:03:18.867 に答える
1

それをxmlに保存して戻すことから始め、以下のメソッドの修正バージョンを使用して読み取りと書き換えを行い、ラインフィードとタブを挿入します。これを行うには、rdr.Depthを使用してタブ数を取得し、WriteEndElement)を呼び出す直前にwtr.WriteRaw( "\ r \ n" + new String('\ t'、tabCount))を使用して非重要な空白。申し訳ありませんが、これはテストされていないコードですが、私があなたを得ることができる限り近いです。

    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)
                );
        }
    }
于 2009-09-04T02:05:48.430 に答える
1

xml プラグインを使用した WinMerge (無料、GPL)

于 2009-09-01T23:07:03.110 に答える
1

差分ツールを変更すると問題が解決する可能性があります。他のすべては問題なく動作するようです。WinMergeなどの一部の差分ツールには、ルールを定義するために正規表現を指定することもできますが、無視したい差分をフィルタリングするオプションがあります。

于 2009-09-03T13:03:25.837 に答える
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 のオプションとして適切な形式のライターに追加されただけでよいでしょう。

差分ツールの変更がオプションではない場合があります (またはそもそも問題でさえありません) ツールを介して perforce のようなシステムを使用して変更を自動マージする場合、変更をできるだけアトミックに保つことが最善です。

たとえば...最後の属性が1人によって変更され、追加の属性が別の人によって最後に追加された場合、どの行に終了> (または/>)を含める必要があるかに基づいて人為的な競合を作成する理由はありません)。このシナリオの最善の解決策は、閉じ括弧が独自の行にあり、競合をすべて回避することです。

于 2012-06-01T08:54:56.613 に答える
0

多くのファイルを変更しているように聞こえるので、これは実用的ではないかもしれませんが、VS でファイルを開いて保存すると、標準の書式設定が復元されます。

于 2009-09-04T14:51:38.937 に答える