4

ここでトリッキーな質問が来ます。

次のような MainFile.XML という 1 つのファイルを取得しました。

<xml>
  <header>
     <some></some>
     <addThis></addThis>
  </header>
  <footer></footer>
  <this>
    <is>
      <deep>
        <like></like>
     </deep>
   </is>
  </this>
<test></test>
<page></page>
<addThis></addThis>

もう 1 つのファイル、LangFile.XML は次のようになります。

<xml>
  <header>
    <some>English file</some>
  </header>
  <footer>Footer</footer>
  <this>
    <is>
      <deep>
        <like>Hey</like>
      </deep>
    </is>
  </this>
  <test>Something</test>
</xml>

LangFile.XML を更新して MainFile.XML と一致させたいのですが、すべての Text 値を LangFile に保持する必要があります。

更新後、LangFile を次のようにしたい: EXPECTED OUTPUT

<xml>
  <header>
    <some>English file</some>
    <addThis></addThis>
  </header>
  <footer>Footer</footer>
  <this>
  <is>
    <deep>
      <like>Hey</like>
    </deep>
  </is>
  </this>
  <test>Something</test>
  <page></page>
  <addThis></addThis>
</xml>

この回答を見てきましたが、ファイルを更新して値を保持する必要があります... 2 つのテキスト ファイルを 1 行ずつ比較する

トリッキーな部分はネスティングです。1 レベルから X レベルの深さまで何でもかまいません...

私の問題は、ツリーを深くするときに行を行ごとに比較する方法がわからないことです。このようなことを試しましたが、立ち往生しています...特定の子孫を新しいリストに追加する方法がわかりません。

String directory = @"C:\Utv\XmlTest";

var mainFile = XDocument.Load(Path.Combine(directory, "MainFile.XML"));
var langFile = XDocument.Load(Path.Combine(directory, "LangFile.XML"));

//Get all descendant nodes
var mainFileDesc = mainFile.Root.Descendants().ToList();
var langFileDesc = langFile.Root.Descendants().ToList();

//Loop through the mainfile
for(var i = 0; i < mainFileDesc.Count(); i++)
{
    var mainRow = mainFileDesc[i];
    var langRow = langFileDesc[i];

    //Compare the rows descendants, if not the same, add the mainRow to the langRow
    if(mainRow.Descendants().Count() != langRow.Descendants().Count())
    {
        //Here I want to check if the mainRow != the langRow
                    //if not, add the mainRow to the langFile list
                    if(mainRow != langRow)
                    {
                      langFileDesc.Insert(i, mainRow);
                    }
    }
}

現在、次のエラーが発生しています。

var langRow = langFileDesc[i];
Message Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index 

これは、リストの長さが同じではないためです。そのため、リストに追加する必要があります...

4

2 に答える 2

2

私が理解しているように、2 つのファイルの構造が似ていることを考慮して、xml ファイルを別の xml ファイルで更新する必要があります。その場合、 xpath でこれを行うことができます。これは次のようになります。

   private static void Main(string[] args)
    {
        try
        {
            XmlDocument xml1 = new XmlDocument();
            xml1.Load(@"C:\testxml\MainFile.xml");
            XPathNavigator nav = xml1.CreateNavigator();

            //Create the langFile Navigator
            XPathDocument xml2 = new XPathDocument(@"C:\testxml\LangFile.xml");
            XPathNavigator nav2 = xml2.CreateNavigator();
            //Select all text nodes.
            var nodes = nav2.SelectDescendants(XPathNodeType.Text, true);
            while (nodes.MoveNext())
            {
                //Update the MainFile with the values in the LangFile

                var c = nav.SelectSingleNode(GetPath(nodes.Clone().Current));//(1*)
                if(c != null)
                {
                    c.MoveToFirstChild();
                    c.SetValue(nodes.Current.Value);
                }
            }
            Console.WriteLine(xml1.InnerXml);
            Console.ReadKey();
        }
        catch
        {
        }
    }
    private static string GetPath(XPathNavigator navigator)
    {
        string aux =string.Empty;
        while (navigator.MoveToParent())
        {
            aux = navigator.Name + "/"+aux;
        }
        return "/" + (aux.EndsWith("/")?aux.Remove(aux.LastIndexOf('/')):aux);
    }

これにより、ファイルがどのくらいネストされているかを知る必要はありませんが、xml に同じレベルに同じ名前のノードが複数ある場合は、(*1) コメントの行で管理する必要があります。これが役立つことを願っています。

于 2013-10-21T23:43:19.303 に答える
2

おそらくこれを再帰的に行いたいでしょう。単純なファイルのコピーはあなたが望むものではないと思います。

これを書いている間、あなたはもう一方を答えとしてチェックしたと思います。うまくいくことを願っていますが、別のアプローチがあります。私のアプローチはもっと複雑に見えるので、マリアーノがうまく機能するなら.

/// <summary>
/// Copy A to B where B doesn't have A nodes.
/// </summary>
public static void EvenUp(XElement A, XElement B)
{
    XNode lastB = null, nodeA = null, nodeB = null;

    Action Copy_A_To_B = () =>
    {
        if (null == lastB)
            B.AddFirst(nodeA);
        else
            lastB.AddAfterSelf(nodeA);
    };

    var listA = A.Nodes().ToList();
    var listB = B.Nodes().ToList();
    int a, b;

    for (a = 0, b = 0; a < listA.Count && b < listB.Count; a++, b++)
    {
        nodeA = listA[a];
        nodeB = listB[b];

        XElement xA = nodeA as XElement,
            xB = nodeB as XElement;

        XText tA = nodeA as XText,
            tB = nodeB as XText;

        if (null != xA && null != xB)
        {
            if (xA.Name.LocalName == xB.Name.LocalName)
                EvenUp(xA, xB);
            else
            {
                Copy_A_To_B();
                EvenUp(A, B); // Restart this iteration for various reasons such as 
                                // the next nodeA might be the same as current nodeB
                return;
            }
        }
        else if (null != xA)
            Copy_A_To_B();
        else if (null != tA && null != tB)
        {
            if (tA.Value != tB.Value)
                tB.Value = tA.Value;
        }
        else if (null != tA)
            Copy_A_To_B();

        lastB = nodeB;
    }
    for (; a < listA.Count; a++)
    {
        nodeA = listA[a];
        Copy_A_To_B();
        if (null == lastB)
            lastB = B.FirstNode;
        else
            lastB = lastB.NextNode;
    }
}

これでテストできます:

XElement mainFile = XElement.Load("xmlfile1.xml");
XElement langFile = XElement.Load("xmlfile2.xml");

EvenUp(mainFile, langFile);

Console.WriteLine(langFile.ToString());
Console.ReadLine();

その後、反対方向にコピーしたい場合は、単純にもう一度呼び出しますが、引数を切り替えてください。このEvenUp(langFile, mainFile)場合、両方のファイルが複製されます。

于 2013-10-22T17:25:31.193 に答える