C#中使用Linq查询XML:tag.descendants无法查询所有后代元素。

3

我在这个网站上还比较新,这是我的第一个问题。我已经阅读了文档,但如果我违反任何行为准则,请提前道歉。

这是我的问题:

我有一个XML文件流。我的目标是获取属性“名称”,“类型”以及关键字(由于明显的原因已更改)。

<YourKey>
<Product_Key Name="eMbedded Visual C++ 4.0">
<Key ID="5" Type="Static Activation Key" ClaimedDate="">BBBBB-QW36D-DPT6T-BBBB-ZZZZZ</Key>
</Product_Key>
<Product_Key Name="Windows 10 Home">
<Key ID="1251" Type="Retail" ClaimedDate="1/25/2017">ZZZZZ-6GBG7-ZZZZZ-8JG23-FM47H</Key>
<Key ID="1251" Type="Retail" ClaimedDate="8/23/2016">FEFEF-FVD7K-EEEEF-BEBEB-VMHX7</Key>
<Key ID="1251" Type="Retail" ClaimedDate="4/28/2016">EEZZE-GYB6P-ZZZEE-R72PQ-EEEEZ</Key>
</Product_Key>
</YourKey>

我创建了一个类来保存数据。
public class MsProduct
    {
        public string Name { get; set; }
        public string Type { get; set; }
        public List<string> key { get; set; }
    }

我创建了一个 MsProduct 列表,将 var list(见下文)的每个元素添加到我的对象中。

我创建了一个 Linq 查询,如果没有 Key = (List<string>)keys,它可以编译通过,但我只得到 Name, Type 值为空(如果数据不存在就替换为空格)。

当我添加 Key = (List<string>)keys 时,系统会抛出 "System.InvalidCastException"。

以下是我的查询:

var productName = XDocument.Load(fileXml);
var list = from product in productName.Descendants("YourKey")
                   let name = product.Attribute("Name")
                   let type = product.Attribute("Type")
                   let keys = product.Elements("Key")
                   select new MsProduct
                   {
                       Name = (string)name,
                       Type = (string)type,
                       Key = (List<string>)keys
                   };

有人知道如何查询我的文件并填充我的类吗?

提前致谢!


1
类型是键的属性,而不是产品。请注释该行并检查。还有一件事,您的XML无效。 - A3006
感谢您的快速回复。XML直接来自Microsoft,这是我MSDN订阅的导出。我没有创建代码;)。密钥已经在下面的答案中得到了解答,现在我想知道如何完成“类型”。 - Thomas Alsteens
2个回答

2

您的密钥不是字符串,而是XElements,您无法将其转换为string。根据您想要获取的内容,您可以执行以下操作:

 Key = (List<string>)keys.Select(x=>x.Value).ToList()

或者
 Key = (List<string>)keys.Select(x=>x.ToString()).ToList()

但是你的xml文件里将什么都得不到,因为你查询的不是产品,而是YourKey,要获取产品,请将第一行更改为:

var list = from product in productName.Descendants("Product_Key")

如果您想获得类型,您应该考虑到您有多个Type pro产品。您可以将类型查询到列表中作为键,或者确定它们都是相同的,因此您可以只取第一个:

var list = from product in productName.Descendants("Product_Key")
           let name = product.Attribute("Name")            
           let keys = product.Elements("Key")
           select new MsProduct
           {
               Name = (string)name,
               Type = keys.First().Attribute("Type").Value,
               Key = (List<string>)keys.Select(x=>x.Value).ToList()
           };

谢谢您的快速回答。这解决了我在键列表方面遇到的问题,但我的 type 仍然为空。我将其更改为: let type = productName.Descendants("Key").Attributes("Type")Type = (string)type.Select(x=> x.Value).ToString(),但现在,Type 的值是 " Type "System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Xml.Linq.XAttribute,System.String]" string " - Thomas Alsteens
你想看到哪种类型?例如,“静态激活密钥”? - Maksim Simkin
是的,我在文件中有静态激活密钥、零售或多重激活信息,我需要这些信息来运行我的软件。 - Thomas Alsteens

2

你不需要那些 let 语句。你需要从键中获取值。

var list = from product in productName.Descendants("Product_Key")
               where product.Attribute("Name").Value == "YourKey"
             //  let name = product.Attribute("Name")
             //  let type = product.Attribute("Type")
             //  let keys = product.Elements("Key")
               select new MsProduct
               {
                   Name = (string)product.Attribute("Name"),
                   Type = product.Elements("Type").First().Attribute("Type").Value,
                   Key = product.Elements("Key").Select(e=>e.Value).ToList()
               };

但是 Elements("Type").First()显然是一个值得质疑的定义。
一个ProductKey的类型并不是唯一的,它可以有多个类型。


它确实解决了我的“类型”问题。非常感谢!!!您介意我问一下为什么这是一个有问题的定义吗? - Thomas Alsteens
因为 XML 明确允许一个 Product_Key 有不同的类型,所以在这里说“the”类型会导致基数错误。 - H H

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接