【问题标题】:LINQ to XML: What is the most effective way to move nodes up and downLINQ to XML:上下移动节点的最有效方法是什么
【发布时间】:2010-09-12 17:35:09
【问题描述】:

我需要在某些节点之前和之后移动兄弟节点。这是我正在使用的代码

<tabs>
     <tab>
          <name>Overview</name>
     </tab>
     <tab>
          <name>Testing</name>
     </tab>
     <tab>
          <name>Performance</name>
     </tab>
     <tab>
          <name>Braking</name>
     </tab>
</tabs>

我想将带有测试的选项卡移到概览上方。我将如何使用 linq to XML 来解决这个问题?

【问题讨论】:

  • 兄弟节点在哪个节点之前/之后移动的规则是什么?或者你只是在问如何移动节点?
  • 这正是我所需要的。我需要知道如何移动节点。谢谢

标签: c# xml linq linq-to-xml


【解决方案1】:

您可以通过移除元素然后将它们重新插入到所需位置来移动元素:

var doc = XDocument.Parse(@"<tabs>...</tabs>");

var tab = doc.Root.Elements().ElementAt(1);
tab.Remove();
doc.Root.AddFirst(tab);

或者,您可以按所需顺序从现有元素创建一个新文档:

var doc = XDocument.Parse(@"<tabs>...</tabs>");

var tabs = doc.Root.Elements();

var result = new XDocument(
                 new XElement("tabs", 
                     tabs.ElementAt(1),
                     tabs.ElementAt(0),
                     tabs.ElementAt(2)));

我还没有测试过,但这可能有效:

void Swap(XElement a, XElement b)
{
    var c = new XElement("dummy");
    a.ReplaceWith(c);
    b.ReplaceWith(a);
    c.ReplaceWith(b);
}

【讨论】:

  • 我真的对将节点移动到第一个或最后一个位置不感兴趣,我只是想交换节点。如果当前选项卡是测试,我将如何交换测试和性能?
  • 另外,你的例子假设我知道有多少兄弟姐妹?如果我不知道有多少兄弟姐妹,但我知道在兄弟姐妹中的某处存在测试元素,我将如何交换这些元素?
  • @Luke101:我添加了一个解决方案来交换到 XDocument 中的任意 XElement。不过我还没有测试过。
【解决方案2】:

抱歉,这是 VB.NET 和 XML Literals,但它可以在 C# 中完成。这里的想法是使用Reverse扩展方法:

Sub Main()
        Dim tab = <tabs>
                      <tab>
                          <name>Overview</name>
                      </tab>
                      <tab>
                          <name>Testing</name>
                      </tab>
                      <tab>
                          <name>Performance</name>
                      </tab>
                      <tab>
                          <name>Braking</name>
                      </tab>
                  </tabs>
        Console.WriteLine(SwapElements("Testing", "Performance", tab).ToString)
        Console.ReadLine()
    End Sub
    Function SwapElements(ByVal firstElement As String, ByVal secondElement As String, ByVal tab As XElement) As XElement
        Dim swapped = tab.Elements.Where(Function(e) e.Value = firstElement Or e.Value = secondElement).Reverse
        Dim middle = tab.Elements.SelectMany(Function(e) e.ElementsAfterSelf.Where(Function(f) e.Value = firstElement).TakeWhile(Function(g) g.Value <> secondElement))
        swapped.ElementAt(0).AddAfterSelf(middle)
        Return <<%= tab.Name %>>
                   <%= tab.Elements.Select(Function(e) e.ElementsBeforeSelf.Where(Function(f) e.Value = firstElement)) %>
                   <%= swapped %>
                   <%= tab.Elements.Select(Function(e) e.ElementsAfterSelf.Where(Function(f) e.Value = secondElement)) %>
               </>
    End Function

【讨论】:

  • 哇..读了几遍后,我发现这是解决这个问题的最优雅的方法。对不起,我已经选择了答案。我已经实施了您的解决方案。谢谢
  • 如果两个元素不相邻怎么办?
  • @dtb:那么您需要更多代码。查询firstElement 之后和secondElement 之前的所有内容,并对.Add 执行swapped。我已经用两行代码更新了上面的代码以反映这一点。
【解决方案3】:

你可以使用类似的东西:

    var tests = from node in doc.Descendants("name") where node.Value == "Testing" select node;
    var test = tests.Single();
    var tab = test.Parent;
    var tabs = tab.Parent;
    tab.Remove();
    tabs.AddFirst(tab);

不确定您的 XML 结构有多少是固定的/已知的。

【讨论】:

  • 我相信这段代码将测试移到了第一位。现在我将如何移动交换测试和性能?我真的对将节点移动到 firat 或最后一个我只想交换节点的地方不感兴趣。如何做到这一点?
【解决方案4】:

我知道这篇文章已经过时了,但我今天遇到了同样的问题并最终以这种方式解决了它:

private void SwapXNodes(bool up, int inUniqueID)
    {
        XElement currNode = DocumentManager.xMainDocument.XPathSelectElement("//*[@UniqueID='" + inUniqueID + "']"); // find 

        if (up)
        {
            if (currNode.PreviousNode != null)
            {
                XElement xPrevious = new XElement((XElement)currNode.PreviousNode); // copy of previous node

                currNode.PreviousNode.ReplaceWith(currNode); // previous node equal to me
                currNode.ReplaceWith(xPrevious); // Now I should be equal to previous node
            }
        }
        else
        {
            if (currNode.NextNode != null)
            {
                XElement xNext = new XElement((XElement)currNode.NextNode); // copy of Next node

                currNode.NextNode.ReplaceWith(currNode); // Next node equal to me
                currNode.ReplaceWith(xNext); // Now I should be equal to Next node copy
            }
        }
    }

【讨论】:

    猜你喜欢
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-12
    相关资源
    最近更新 更多