在正确的位置添加 Linq to XML 的新条目(基于数值属性)

Adding a new entry with Linq to XML at the right position (based on numerical attribute)

提问人:Andrew Truckle 提问时间:9/12/2023 最后编辑:Andrew Truckle 更新时间:9/13/2023 访问量:37

问:

我想出了这个函数来保存或更新XML文件中的条目。

public void SetOutlineInfo(string talksdatabase, int talknumber, string languageCode, bool talkExcluded, DateTime dateExcudedFrom, string excludedNote)
{
    try
    {
        XDocument doc = XDocument.Load(talksdatabase);
        var ptLang = doc.Descendants(languageCode).FirstOrDefault();
        if (ptLang != null)
        {
            var ptInfo = ptLang
                            .Descendants("PublicTalk")
                            .Where(p => p.Attribute("Number").Value == talknumber.ToString()).FirstOrDefault();
            if (ptInfo != null)
            {
                ptInfo.Attribute("Excluded").Value = talkExcluded ? "true" : "false";
                ptInfo.Attribute("ExcludedFromDate").Value = dateExcudedFrom.ToString("yyyy-MM-dd");
                ptInfo.Attribute("ExcludedNote").Value = excludedNote;
            }
            else
            {
                ptLang.Add(new XElement("PublicTalk",
                    new XAttribute("Number", talknumber),
                    new XAttribute("Excluded", talkExcluded),
                    new XAttribute("ExcludedFromDate", dateExcudedFrom.ToString("yyyy-MM-dd")),
                    new XAttribute("ExcludedNote", excludedNote)
                    ));
            }

            doc.Save(talksdatabase);
        }
    }
    catch (Exception ex)
    {
        SimpleLog.Log(ex);
    }
}

唯一的问题是添加新条目不会将其添加到正确的数字位置(属性)。Number

我做了一些搜索,它们都显示阅读记录并使用 .但我在写记录。orderby


按照评论中的要求。

下面是一个 XML:

<?xml version="1.0" encoding="utf-8"?>
<PublicTalkTitles>
  <eng>
    <PublicTalk Number="47" Excluded="true" ExcludedFromDate="2019-04-01" ExcludedNote="S-147 19.03" />
  </eng>
</PublicTalkTitles>

当添加一个新条目时,说谈话编号 1:

<?xml version="1.0" encoding="utf-8"?>
<PublicTalkTitles>
  <eng>
    <PublicTalk Number="1" Excluded="true" ExcludedFromDate="2023-09-12" ExcludedNote="1" />
    <PublicTalk Number="47" Excluded="true" ExcludedFromDate="2019-04-01" ExcludedNote="S-147 19.03" />
  </eng>
</PublicTalkTitles>
C# LINQ-to-XML

评论

1赞 Lukasz Nowakowski 9/12/2023
可以尝试 XNode.AddAfterSelf (learn.microsoft.com/en-us/dotnet/api/...)。它应该在 PublicTalk 节点上调用,然后你要添加元素。
0赞 Andrew Truckle 9/12/2023
@LukaszNowakowski 因此,我必须遍历现有节点集,以决定在哪个点添加它。
0赞 Charlieface 9/12/2023
请显示您现有的 XML 和要更改的内容
1赞 Lukasz Nowakowski 9/12/2023
@AndrewTruckle,是的。
0赞 jdweng 9/12/2023
Descendants 返回一个数组。因此,只需添加索引 ptLang[0]。加

答:

0赞 Andrew Truckle 9/12/2023 #1

根据使用建议,我修改了该函数:AddBeforeSelf

public void SetOutlineInfo(string talksdatabase, int talknumber, string languageCode, bool talkExcluded, DateTime dateExcudedFrom, string excludedNote)
{
    try
    {
        XDocument doc = XDocument.Load(talksdatabase);
        var ptLang = doc.Descendants(languageCode).FirstOrDefault();
        if (ptLang != null)
        {
            var ptInfo = ptLang
                            .Descendants("PublicTalk")
                            .Where(p => p.Attribute("Number").Value == talknumber.ToString()).FirstOrDefault();
            if (ptInfo != null)
            {
                ptInfo.Attribute("Excluded").Value = talkExcluded ? "true" : "false";
                ptInfo.Attribute("ExcludedFromDate").Value = dateExcudedFrom.ToString("yyyy-MM-dd");
                ptInfo.Attribute("ExcludedNote").Value = excludedNote;
            }
            else
            {
                var ptList = ptLang.Descendants("PublicTalk");
                bool bAdd = true;
                foreach ( var pt in ptList )
                {
                    if (Convert.ToInt32(pt.Attribute("Number").Value) > talknumber)
                    {
                        pt.AddBeforeSelf(new XElement("PublicTalk",
                            new XAttribute("Number", talknumber.ToString()),
                            new XAttribute("Excluded", talkExcluded),
                            new XAttribute("ExcludedFromDate", dateExcudedFrom.ToString("yyyy-MM-dd")),
                            new XAttribute("ExcludedNote", excludedNote)
                            ));
                        bAdd = false;
                        break;
                    }
                }

                if(bAdd)
                {
                    ptLang.Add(new XElement("PublicTalk",
                        new XAttribute("Number", talknumber.ToString()),
                        new XAttribute("Excluded", talkExcluded),
                        new XAttribute("ExcludedFromDate", dateExcudedFrom.ToString("yyyy-MM-dd")),
                        new XAttribute("ExcludedNote", excludedNote)
                        ));
                }
            }

            doc.Save(talksdatabase);
        }
    }
    catch (Exception ex)
    {
        SimpleLog.Log(ex);
    }
}
1赞 Charlieface 9/13/2023 #2

您需要首先过滤所有节点,然后采用该数字。您需要将其解析为 an 才能正确进行此过滤和排序。<= talknumberMaxByint

那么该节点是:

  • 你想要的那个
    • 改变它
  • 或之前的那个
    • AddBeforeSelf
  • 或 null
    • 在父母身上使用。AddFirst

    var ptLang = doc.Element("PublicTalkTitles").Element(languageCode);
    if (ptLang != null)
    {
        var pt = ptLang.Elements("PublicTalk");
        var ptInfo = pt
            .Where(p => int.Parse(p.Attribute("Number").Value) <= talknumber)
            .MaxBy(p => int.Parse(p.Attribute("Number").Value));
        if (int.Parse(ptInfo?.Attribute("Number").Value ?? "0") == talknumber)
        {
            ptInfo.Attribute("Excluded").Value = talkExcluded ? "true" : "false";
            ptInfo.Attribute("ExcludedFromDate").Value = dateExcudedFrom.ToString("yyyy-MM-dd");
            ptInfo.Attribute("ExcludedNote").Value = excludedNote;
        }
        else
        {
            var newElem = new XElement("PublicTalk",
                                    new XAttribute("Number", talknumber),
                                    new XAttribute("Excluded", talkExcluded),
                                    new XAttribute("ExcludedFromDate", dateExcudedFrom.ToString("yyyy-MM-dd")),
                                    new XAttribute("ExcludedNote", excludedNote)
                                   );
            if (ptInfo != null)
                ptInfo.AddAfterSelf(newElem);
            else
                ptLang.AddFirst(newElem);
        }
    }

dotnetfiddle

如果你没有,你可以改用效率较低的方法。MaxByOrderByDescending.FirstOrDefault

var ptInfo = pt
    .Where(p => int.Parse(p.Attribute("Number").Value) <= talknumber)
    .OrderByDescending(p => int.Parse(p.Attribute("Number").Value))
    .FirstOrDefault();

评论

0赞 Andrew Truckle 9/13/2023
谢谢。我收到一个语法错误,告诉我我无法使用。我正在使用框架 4.6.2,目前无法更改它。MaxBy
1赞 Charlieface 9/13/2023
好的,你可以使用,见编辑OrderByDescending
0赞 Andrew Truckle 9/13/2023
谢谢;我只是将Visual Studio升级到最新版本,然后我将尝试此调整后的代码。