gpt4 book ai didi

c# - 如何使用 C# 和 LINQ 深入提取 XML 中的信息?

转载 作者:数据小太阳 更新时间:2023-10-29 01:43:26 24 4
gpt4 key购买 nike

这是我在 StackOverflow 上的第一篇文章,所以请多多包涵。如果我的代码示例有点长,我先表示歉意。

使用 C# 和 LINQ,我试图识别一系列第三级 id元素(在本例中为 000049)在一个更大的 XML 文件中。每三级id是独一无二的,我想要的是基于每个人的一系列后代信息。更具体地说,如果 type == Alocation type(old) == vaultlocation type(new) == out , 然后我想选择 id .下面是我正在使用的 XML 和 C# 代码。

总的来说,我的代码有效。如下所示,它将返回 id 000049 两次,这是正确的。但是,我发现了一个小故障。如果我删除第一个 history包含 type == A 的 block ,我的代码仍然返回 id 000049 两次,而它应该只返回一次。我知道为什么会这样,但我想不出更好的方法来运行查询。有没有更好的方法来运行我的查询以获得我想要的输出并仍然使用 LINQ?

我的 XML:

<?xml version="1.0" encoding="ISO8859-1" ?>
<data type="historylist">
<date type="runtime">
<year>2011</year>
<month>04</month>
<day>22</day>
<dayname>Friday</dayname>
<hour>15</hour>
<minutes>24</minutes>
<seconds>46</seconds>
</date>
<customer>
<id>0001</id>
<description>customer</description>
<mediatype>
<id>kit</id>
<description>customer kit</description>
<volume>
<id>000049</id>
<history>
<date type="optime">
<year>2011</year>
<month>04</month>
<day>22</day>
<dayname>Friday</dayname>
<hour>03</hour>
<minutes>00</minutes>
<seconds>02</seconds>
</date>
<userid>batch</userid>
<type>OD</type>
<location type="old">
<repository>vault</repository>
<slot>0</slot>
</location>
<location type="new">
<repository>out</repository>
<slot>0</slot>
</location>
<container>0001.kit.000049</container>
<date type="movedate">
<year>2011</year>
<month>04</month>
<day>22</day>
<dayname>Friday</dayname>
</date>
</history>
<history>
<date type="optime">
<year>2011</year>
<month>04</month>
<day>22</day>
<dayname>Friday</dayname>
<hour>06</hour>
<minutes>43</minutes>
<seconds>33</seconds>
</date>
<userid>vaultred</userid>
<type>A</type>
<location type="old">
<repository>vault</repository>
<slot>0</slot>
</location>
<location type="new">
<repository>out</repository>
<slot>0</slot>
</location>
<container>0001.kit.000049</container>
<date type="movedate">
<year>2011</year>
<month>04</month>
<day>22</day>
<dayname>Friday</dayname>
</date>
</history>
<history>
<date type="optime">
<year>2011</year>
<month>04</month>
<day>22</day>
<dayname>Friday</dayname>
<hour>06</hour>
<minutes>43</minutes>
<seconds>33</seconds>
</date>
<userid>vaultred</userid>
<type>S</type>
<location type="old">
<repository>vault</repository>
<slot>0</slot>
</location>
<location type="new">
<repository>out</repository>
<slot>0</slot>
</location>
<container>0001.kit.000049</container>
<date type="movedate">
<year>2011</year>
<month>04</month>
<day>22</day>
<dayname>Friday</dayname>
</date>
</history>
<history>
<date type="optime">
<year>2011</year>
<month>04</month>
<day>22</day>
<dayname>Friday</dayname>
<hour>06</hour>
<minutes>45</minutes>
<seconds>00</seconds>
</date>
<userid>batch</userid>
<type>O</type>
<location type="old">
<repository>out</repository>
<slot>0</slot>
</location>
<location type="new">
<repository>site</repository>
<slot>0</slot>
</location>
<container>0001.kit.000049</container>
<date type="movedate">
<year>2011</year>
<month>04</month>
<day>22</day>
<dayname>Friday</dayname>
</date>
</history>
<history>
<date type="optime">
<year>2011</year>
<month>04</month>
<day>22</day>
<dayname>Friday</dayname>
<hour>11</hour>
<minutes>25</minutes>
<seconds>59</seconds>
</date>
<userid>ihcmdm</userid>
<type>A</type>
<location type="old">
<repository>out</repository>
<slot>0</slot>
</location>
<location type="new">
<repository>site</repository>
<slot>0</slot>
</location>
<container>0001.kit.000049</container>
<date type="movedate">
<year>2011</year>
<month>04</month>
<day>22</day>
<dayname>Friday</dayname>
</date>
</history>
<history>
<date type="optime">
<year>2011</year>
<month>04</month>
<day>22</day>
<dayname>Friday</dayname>
<hour>11</hour>
<minutes>25</minutes>
<seconds>59</seconds>
</date>
<userid>ihcmdm</userid>
<type>S</type>
<location type="old">
<repository>out</repository>
<slot>0</slot>
</location>
<location type="new">
<repository>site</repository>
<slot>0</slot>
</location>
<container>0001.kit.000049</container>
<date type="movedate">
<year>2011</year>
<month>04</month>
<day>22</day>
<dayname>Friday</dayname>
</date>
</history>
</volume>
...

我的 C# 代码:

IEnumerable<XElement> caseIdLeavingVault =
from volume in root.Descendants("volume")
where
(from type in volume.Descendants("type")
where type.Value == "A"
select type).Any() &&
(from locationOld in volume.Descendants("location")
where
((String)locationOld.Attribute("type") == "old" &&
(String)locationOld.Element("repository") == "vault") &&
(from locationNew in volume.Descendants("location")
where
((String)locationNew.Attribute("type") == "new" &&
(String)locationNew.Element("repository") == "out")
select locationNew).Any()
select locationOld).Any()
select volume.Element("id");

...

foreach (XElement volume in caseIdLeavingVault)
{
Console.WriteLine(volume.Value.ToString());
}

谢谢。


好吧,我又被难住了。鉴于同样的情况和下面@Elian 的解决方案(效果很好),我需要 "optime""movedate" history 的日期用于选择 id .那有意义吗?我希望以这样的方式结束:

select new { 
id = volume.Element("id").Value,

// this is from "optime"
opYear = <whaterver>("year").Value,
opMonth = <whatever>("month").Value,
opDay = <whatever>("day").Value,

// this is from "movedate"
mvYear = <whaterver>("year").Value,
mvMonth = <whatever>("month").Value,
mvDay = <whatever>("day").Value
}

我尝试了很多不同的组合,但是 Attribute s <date type="optime"><date type="movedate">一直挡着我的路,我似乎得不到我想要的。


好的。我找到了一个 solution效果很好:

select new {
caseId = volume.Element("id").Value,

// this is from "optime"
opYear = volume.Descendants("date").Where(t => t.Attribute("type").Value == "optime").First().Element("year").Value,
opMonth = volume.Descendants("date").Where(t => t.Attribute("type").Value == "optime").First().Element("month").Value,
opDay = volume.Descendants("date").Where(t => t.Attribute("type").Value == "optime").First().Element("day").Value,

// this is from "movedate"
mvYear = volume.Descendants("date").Where(t => t.Attribute("type").Value == "movedate").First().Element("year").Value,
mvMonth = volume.Descendants("date").Where(t => t.Attribute("type").Value == "movedate").First().Element("month").Value,
mvDay = volume.Descendants("date").Where(t => t.Attribute("type").Value == "movedate").First().Element("day").Value
};

但是,当它找到 id 时它确实失败了没有 "movedate" .其中一些存在,所以现在我正在努力。


好吧,昨天下午晚些时候我终于找到了我一直想要的解决方案:

var caseIdLeavingSite =
from volume in root.Descendants("volume")
where volume.Elements("history").Any(
h => h.Element("type").Value == "A" &&
h.Elements("location").Any(l => l.Attribute("type").Value == "old" && ((l.Element("repository").Value == "site") ||
(l.Element("repository").Value == "init"))) &&
h.Elements("location").Any(l => l.Attribute("type").Value == "new" && l.Element("repository").Value == "toVault")
)
select new {
caseId = volume.Element("id").Value,
opYear = volume.Descendants("date").Where(t => t.Attribute("type").Value == "optime").First().Element("year").Value,
opMonth = volume.Descendants("date").Where(t => t.Attribute("type").Value == "optime").First().Element("month").Value,
opDay = volume.Descendants("date").Where(t => t.Attribute("type").Value == "optime").First().Element("day").Value,
mvYear = (volume.Descendants("date").Where(t => t.Attribute("type").Value == "movedate").Any() == true) ?
(volume.Descendants("date").Where(t => t.Attribute("type").Value == "movedate").First().Element("year").Value) : "0",
mvMonth = (volume.Descendants("date").Where(t => t.Attribute("type").Value == "movedate").Any() == true) ?
(volume.Descendants("date").Where(t => t.Attribute("type").Value == "movedate").First().Element("month").Value) : "0",
mvDay = (volume.Descendants("date").Where(t => t.Attribute("type").Value == "movedate").Any() == true) ?
(volume.Descendants("date").Where(t => t.Attribute("type").Value == "movedate").First().Element("day").Value) : "0"
};

这满足了@Elian 帮助的要求并获取了必要的额外日期信息。当没有 "movedate" 的元素时,它也说明了那些少数情况。通过使用三元运算符 ?: .

现在,如果有人知道如何提高效率,我仍然很感兴趣。谢谢。

最佳答案

我想你想要这样的东西:

IEnumerable<XElement> caseIdLeavingVault =
from volume in document.Descendants("volume")
where volume.Elements("history").Any(
h => h.Element("type").Value == "A" &&
h.Elements("location").Any(l => l.Attribute("type").Value == "old" && l.Element("repository").Value == "vault") &&
h.Elements("location").Any(l => l.Attribute("type").Value == "new" && l.Element("repository").Value == "out")
)
select volume.Element("id");

您的代码独立检查卷是否有 <history>元素类型 A和一个(不一定相同)<history>具有所需 <location> 的元素元素。

上面的代码检查是否存在 <history>类型均为 A 的元素并包含所需的 <location>元素。

更新:Abatishchev 建议使用 xpath 查询而不是 LINQ to XML 的解决方案,但他的查询过于简单,无法准确返回您要求的内容。以下 xpath 查询可以解决问题,但它也有点长:

data/customer/mediatype/volume[history[type = 'A' and location[@type = 'old' and repository = 'vault'] and location[@type = 'new' and repository = 'out']]]/id

关于c# - 如何使用 C# 和 LINQ 深入提取 XML 中的信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5782655/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com