c# LINQ-to-XML 更新(保存)排序后文件中的元素列表

Posted

技术标签:

【中文标题】c# LINQ-to-XML 更新(保存)排序后文件中的元素列表【英文标题】:c# LINQ-to-XML update (save) list of elements in file after ordering 【发布时间】:2017-07-26 18:46:13 【问题描述】:

我有一个这样的 XML 文件:

<?xml version="1.0" encoding="utf-8"?>
<FooMgr>
    <BlargDate>2017-03-06 10:26:21</BlargDate>
    <Bars>
        <Bar>
            <BarId>222</BarId>
            <BarVal>QWERTY</BarVal>
        </Bar>
        <Bar>
            <BarId>77</BarId>
            <BarVal>DVORAK</BarVal>
        </Bar>
        <Bar>
            <BarId>9999</BarId>
            <BarVal>AZERTY</BarVal>
        </Bar>
    </Bars>
</FooMgr>

我是:

阅读中 添加“栏”元素 按 BarId 降序排列 正在尝试保存更新/排序的 xml 回文件。

虽然我保存后添加的元素在列表中,但保存时并没有保持我在代码中定义的顺序。这是我到目前为止所做的(主要是有效的代码)

//read in the xml file
XDocument doc = XDocument.Load(...);

//add a new 'Bar' element
XElement bar1 = new XElement("Bar",
                      new XElement("BarId", 101),
                      new XElement("BarVal", "HCESAR"));
doc.Element("FooMgr").Element("Bars").Add(bar1);

//sort descending by BarId
IEnumerable<XElement> allBars = doc.Descendants("FooMgr")
                                   .Select(x => x.Element("Bars"))
                                   .Descendants("Bar")
                                   .ToArray();
allBars = allBars.OrderByDescending(s => int.Parse(s.Element("BarId").Value));

//save file
doc.Save(...);

// note: at this point the file successfully saves (along with the 
// new 'bar' value, but the order that is set for allBars does not 
// make it back into the file.

虽然这一行:

allBars = allBars.OrderByDescending(s => int.Parse(s.Element("BarId").Value));

似乎确实对代码中的“条形”元素进行了正确排序,当我将其保存回文件时,订单不会保留。

有什么想法吗?

【问题讨论】:

【参考方案1】:

您可以在调用Save 方法之前执行此操作:

//Remove bar elements from your doc
doc.Element("FooMgr").Element("Bars").Elements("Bar").Remove();
//Add the ordered bar nodes
doc.Element("FooMgr").Element("Bars").Add(allBars);

//save file
doc.Save(...);

更多关于Remove扩展方法和Add方法的信息

【讨论】:

@Dispersia,引用 OP:“但是为 allBars 设置的顺序并没有返回到文件中。” @octavioccl 这正是我一直在寻找的,并且按预期工作。谢谢! @Dispersia 对不起,如果我的问题有点模糊 好吧,显然@russellelbert 认为这是解决方案;) 我误解了你在做什么,抱歉。编辑您的答案,以便我删除反对票。 没问题@Dispersia ;)【参考方案2】:

首先,您的 xml 无效,我猜正确的是:

<?xml version="1.0" encoding="utf-8"?>
<FooMgr>
    <BlargDate>2017-03-06 10:26:21</BlargDate>
    <Bars>
        <Bar>
            <BarId>222</BarId>
            <BarVal>QWERTY</BarVal>
        </Bar>
        <Bar>
            <BarId>77</BarId>
            <BarVal>DVORAK</BarVal>
        </Bar>
        <Bar>
            <BarId>9999</BarId>
            <BarVal>AZERTY</BarVal>
        </Bar>
    </Bars>
</FooMgr>

你的 allBars 只是一个节点集合,它不属于任何节点,所以你需要把它挂在 Bars 下,我建议先删除那里的所有项目:

XElement bar1 = new XElement("Bar",
    new XElement("BarId", 101),
    new XElement("BarVal", "HCESAR"));
doc.Element("FooMgr").Element("Bars").Add(bar1);

//sort descending by BarId
IEnumerable<XElement> allBars = doc.Descendants("FooMgr")
    .Select(x => x.Element("Bars"))
    .Descendants("Bar")
    .ToArray();

allBars = allBars.OrderByDescending(s => int.Parse(s.Element("BarId").Value));

doc.Element("FooMgr").Element("Bars").RemoveAll();
doc.Element("FooMgr").Element("Bars").Add(allBars);

【讨论】:

哎呀,对无效的 XML 感到抱歉 - 我在“复制/粘贴/编辑”条目上有所松懈。我会尽快更新它。您发布的代码是我需要的,但 octavioccl 击败了您的答案。谢谢!【参考方案3】:

在 VB 中是这样的

    Dim doc As XElement
    ' to load from a file
    'xe = XElement.Load(yourpath)
    ' for testing
    doc = <FooMgr>
              <BlargDate>2017-03-06 10:26:21</BlargDate>
              <Bars>
                  <Bar>
                      <BarId>222</BarId>
                      <BarVal>QWERTY</BarVal>
                  </Bar>
                  <Bar>
                      <BarId>77</BarId>
                      <BarVal>DVORAK</BarVal>
                  </Bar>
                  <Bar>
                      <BarId>9999</BarId>
                      <BarVal>AZERTY</BarVal>
                  </Bar>
              </Bars>
          </FooMgr>

    doc.<Bars>.LastOrDefault.Add(<Bar>
                                     <BarId>101</BarId>
                                     <BarVal>HCESAR</BarVal>
                                 </Bar>)

    Dim ie As List(Of XElement) = doc.<Bars>.Elements.OrderBy(Function(el) Integer.Parse(el.<BarId>.Value)).ToList
    doc.<Bars>.Elements.Remove()
    doc.<Bars>.FirstOrDefault.Add(ie)
    ' to save file
    ' doc.Save(yourpath)

【讨论】:

以上是关于c# LINQ-to-XML 更新(保存)排序后文件中的元素列表的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中使用 LINQ-To-XML 解析具有多个列表和类对象的 XML 数据

如何使用 linq-to-xml 查询简化此功能?

LINQ-to-XML 中 XSD.EXE 的替代方案?

Linq-to-XML XElement.Remove() 留下不需要的空白

Vue.js 可排序列表 - 通过 AJAX 更新模型并保存更改位置

使用 c# winforms 将数据更新/保存到 SQL 数据库表