提问人:Andrew Truckle 提问时间:8/3/2023 最后编辑:Andrew Truckle 更新时间:8/3/2023 访问量:62
是否可以使用 LINQ to XML 从此 XML 文件中提取所需的日期信息?
Can I use LINQ to XML to extract the required date information from this XML file?
问:
这是否可以通过 LINQ to XML 实现?
我有一个对象,我获得了上次邀请日期早于今天的所有项目的列表:List<Congregation>
var congs =_CongregationData.Congregations
.Where(a => a.LastInvited < DateTime.Today)
这是第 1 步。但是我还有另一个XML文件。下面是一个精简的示例(忽略日期,因为它们是编造的):
<AssignmentHistory>
<W20230731>
<PublicTalkInfo>
<PublicTalkTheme>Theme 1</PublicTalkTheme>
</PublicTalkInfo>
</W20230731>
<W20230807>
<PublicTalkInfo>
<PublicTalkTheme>Theme 2</PublicTalkTheme>
</PublicTalkInfo>
</W20230807>
<W20230814>
<PublicTalkInfo>
<MeetingDate>2023-08-20</MeetingDate>
<PublicTalkCongregation>Congregation 1</PublicTalkCongregation>
<PublicTalkTheme>Theme 3</PublicTalkTheme>
</PublicTalkInfo>
</W20230814>
<W20230821>
<PublicTalkInfo>
<MeetingDate>2023-08-27</MeetingDate>
<PublicTalkCongregation>Congregation 2</PublicTalkCongregation>
<PublicTalkTheme>Theme 4</PublicTalkTheme>
</PublicTalkInfo>
</W20230821>
<W20230828>
<PublicTalkInfo>
<MeetingDate>2023-09-03</MeetingDate>
<PublicTalkCongregation>Congregation 3</PublicTalkCongregation>
<PublicTalkTheme>Theme 5</PublicTalkTheme>
</PublicTalkInfo>
</W20230828>
</AssignmentHistory>
我知道这个XML设计得很糟糕(节点都有不同的名称),但这是我必须使用的数据文件。是否可以使用 LINQ to XML 从此 XML 中获取一组记录。WYYYYMMDD
例如,
for(var cong : congs)
{
// 1. Select from history XML all records where PublicTalkCongregation is cong.Name.
// 2. Records must be date descending on MeetingDate.
// 3. We only want the records older than today.
}
换句话说,我是否可以使用 LINQ to XML 来查找 () 在今天之前的最新日期 ()。这样我就可以更新到这个日期。MeetingDate
cong.Name
PublicTalkCongregation
cong.LastInvited
有意义?
更新
我正在尝试建议的答案,但出现异常:
Unhandled Exception: System.ArgumentNullException: Value cannot be null.
Parameter name: element
at System.Xml.Linq.XElement.op_Explicit(XElement element)
at ConsoleApp1.Program.<>c.<Main>b__2_0(XElement x) in D:\My Programs\2022\Backup MSA2\ConsoleApp1\ConsoleApp1\Program.cs:line 24
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at ConsoleApp1.Program.Main(String[] args) in D:\My Programs\2022\Backup MSA2\ConsoleApp1\ConsoleApp1\Program.cs:line 23
我应该澄清一下,一些较旧的分配历史记录条目不会有 \ 元素,应该绕过这些历史周的情况。MeetingDate
PublicTalkCongregation
答:
1赞
jdweng
8/3/2023
#1
请尝试以下操作:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Globalization;
namespace ConsoleApplication2
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement assignments = doc.Descendants("AssignmentHistory").FirstOrDefault();
List<Meeting> meetings = assignments.Elements().Select(x =>
new Meeting()
{
date = DateTime.ParseExact(x.Name.LocalName, "WyyyyMMdd", CultureInfo.InvariantCulture),
meetingDate = x.Descendants("MeetingDate").FirstOrDefault() == null ? new DateTime() : (DateTime)x.Descendants("MeetingDate").FirstOrDefault(),
congregation = (string)x.Descendants("PublicTalkCongregation").FirstOrDefault()
}).ToList();
}
}
}
public class Meeting
{
public DateTime date { get; set; }
public DateTime meetingDate { get; set; }
public string congregation { get; set; }
}
评论
0赞
Andrew Truckle
8/3/2023
谢谢。请参阅我更新的问题。
0赞
jdweng
8/3/2023
尝试注释掉 meetingDate,看看这是否会导致问题。我更新了可能的解决方案。c# 中的 DateTime 不能为 null,我认为这是问题所在。
1赞
jdweng
8/3/2023
我测试了没有会议日期,代码有效。
0赞
Andrew Truckle
8/3/2023
我让它工作!棒。感谢您的帮助!👍
1赞
Serge
8/3/2023
#2
不幸的是,你的xml非常草率,所以无法理解你想要什么。
我一开始会创建一个数据集合
List<Meeting> meetings = XElement.Parse(xml)
.Descendants("PublicTalkInfo")
.Select(x => new Meeting
{
MeetingDate = x.Element("MeetingDate")?.Value == null ?
null : DateTime.Parse(x.Element("MeetingDate").Value),
Congregation = x.Element("PublicTalkCongregation")?.Value
}).ToList();
public class Meeting
{
public DateTime? MeetingDate { get; set; }
public string Congregation { get; set; }
}
在此之后,我可以使用 LINQ 提取我想要的任何数据,例如
Meeting meeting = meetings.Where(x => x.Congregation != "To Be Confirmed")
.OrderBy(x => x.MeetingDate)
.FirstOrDefault();
0赞
Andrew Truckle
8/3/2023
#3
根据提供的两个答案,这是我的最后一个函数(为了完整起见)。
public bool UpdateCongregationDatabase(string historyDatabase)
{
bool bSaveDatabase = false;
try
{
if (_Congregations.Count > 0)
{
var congregationsToReview = _Congregations
.Where(a => a.LastInvited < DateTime.Today);
if(congregationsToReview.Count() > 0)
{
XDocument doc = XDocument.Load(historyDatabase);
List<Meeting> meetings = doc
.Descendants("PublicTalkInfo")
.Select(x => new Meeting
{
MeetingDate = x.Element("MeetingDate")?.Value == null ?
new DateTime() : DateTime.Parse(x.Element("MeetingDate").Value),
Congregation = x.Element("PublicTalkCongregation")?.Value
}).ToList();
if (meetings.Count > 0)
{
foreach (var congregation in congregationsToReview)
{
var historyForCongregation = meetings.Where(x => x.Congregation == congregation.Name && x.MeetingDate < DateTime.Today);
if (historyForCongregation.Count() > 0)
{
var lastInvitedMeeting = historyForCongregation.OrderByDescending(x => x.MeetingDate)
.First();
if (lastInvitedMeeting != null &&
lastInvitedMeeting.MeetingDate > congregation.LastInvited)
{
congregation.LastInvited = (DateTime)lastInvitedMeeting.MeetingDate;
bSaveDatabase = true;
}
}
/*
var lastInvitedMeeting = meetings.Where(x => x.Congregation == congregation.Name && x.MeetingDate < DateTime.Today)
.OrderByDescending(x => x.MeetingDate)
.First();
if (lastInvitedMeeting != null)
{
congregation.LastInvited = (DateTime)lastInvitedMeeting.MeetingDate;
bSaveDatabase = true;
}
*/
}
}
}
}
}
catch (Exception ex)
{
SimpleLog.Log(ex);
}
return bSaveDatabase;
}
我不得不分解后处理代码以避免异常。不确定是否可以解决。
评论