I have come up with this function to save or update an entry in the XML file.
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);
}
}
The only issue is that adding a new entry does not add it in the correct numerical position (the Number
attribute).
I did some searching and they all show reading in records and sorting with orderby
. But I am writing records.
As requested in the comments.
Here is an 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>
When a add a new entry, say talk number 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>
You need to first filter for all nodes which are <= talknumber
then take MaxBy
that number. You need to parse it to an int
in order to do this filtering and sorting correctly.
Then that node is either:
AddBeforeSelf
AddFirst
on the parent. 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);
}
}
If you don't have MaxBy
you can instead use OrderByDescending.FirstOrDefault
which is less efficient.
var ptInfo = pt
.Where(p => int.Parse(p.Attribute("Number").Value) <= talknumber)
.OrderByDescending(p => int.Parse(p.Attribute("Number").Value))
.FirstOrDefault();