使用 Linq 解析 XML
我有以下 XML 文档,我想将其解析为数据集。
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Response Status="OK">
<Item>
<Field Name="ID">767147519</Field>
<Field Name="Name">Music</Field>
<Field Name="Path">Family\Music</Field>
<Field Name="Type">Playlist</Field>
</Item>
</Response>
我想要获取 ID、名称和路径的属性值。
以下是我的尝试:
Dim loaded As XDocument = XDocument.Load(uriString)
Dim name = From c In loaded.Descendants("Item") Select c
For Each result In name
Dim str1 = result.Attribute("ID").Value 'Returns Nothing and causes a validation error
Dim str2 = result.Value ' Returns all the attribute values in one long string (ie "767147519MusicFamilyPlaylist")
Next
任何帮助将不胜感激。
谢谢,
马特
编辑:
按照下面的答案之一,我一直在尝试在我的 Linq 中实现匿名类型,但是我不断遇到错误
对象引用未设置为 对象的实例。
我更新的代码如下:
Dim name = From c In loaded.Descendants("Item") Select c Select sID = c.Element("Field").Attribute("Name").Value, sName = c.Attribute("ID").Value.FirstOrDefault
Dim Id As String = String.Empty
For Each result In name
Id = result.sID
Next
我认为这个错误意味着无法找到属性(“ID”),因此我尝试了几种类似的结果。
有谁能够找出我哪里出了问题并指出我正确的方向。
谢谢,
马特
I have the following XML document which I would like to parse into a DataSet.
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Response Status="OK">
<Item>
<Field Name="ID">767147519</Field>
<Field Name="Name">Music</Field>
<Field Name="Path">Family\Music</Field>
<Field Name="Type">Playlist</Field>
</Item>
</Response>
I am wanting to get the attribute values for ID, Name, and Path.
The following is what I have attempted:
Dim loaded As XDocument = XDocument.Load(uriString)
Dim name = From c In loaded.Descendants("Item") Select c
For Each result In name
Dim str1 = result.Attribute("ID").Value 'Returns Nothing and causes a validation error
Dim str2 = result.Value ' Returns all the attribute values in one long string (ie "767147519MusicFamilyPlaylist")
Next
Any help would be greatly appreciated.
Thanks,
Matt
EDIT:
Following one of the answers below, I have been attempting to implement an anonymous type in my Linq, however I keep encountering the error
Object reference not set to an
instance of an object.
My updated code is as follows:
Dim name = From c In loaded.Descendants("Item") Select c Select sID = c.Element("Field").Attribute("Name").Value, sName = c.Attribute("ID").Value.FirstOrDefault
Dim Id As String = String.Empty
For Each result In name
Id = result.sID
Next
I think this error means that the attribute ("ID") cannot be located, so I have attempted several variations of this with similar results.
Is anyone able to identify where I am going wrong and point me in the right direction.
Thanks,
Matt
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
您可以使用 XPath:(
请务必导入 System.Xml.XPath 命名空间)
或者将其直接添加到 DataTable:
You can use XPath:
(Be sure to import the
System.Xml.XPath
namespace)Or to add it directly to a
DataTable
:另一种使用匿名类型的解决方案:
new 运算符内的丑陋表达式可以与下一个匿名函数缩短:
然后 new 运算符如下所示:
Another one solution with anonymous types:
Ugly expression inside new operator can be shorted with next anonymous function:
Then new operator looks like:
这是我尝试解决您的问题。我只是注意到您希望使用尽可能多的 LINQ,因此我相应地构建了 LINQ 查询。请注意,结果类型(对于“ID”)将是 IEnumerable(),即您需要在其上运行 for every 循环来获取单独的 id,即使是单个项目:
旁注:供将来参考,如果您遇到示例中的 C# 匿名类型“var”,vb 中的等效类型是简单的暗淡,就像上面的查询一样(没有“as type”部分)。
希望这有帮助。
马维里克
Here is my attempt at solution to your problem. I just noticed that you wish to go with as much LINQ as possible so I've structured my LINQ query accordingly. Please note result type (for "IDs") will be IEnumerable() i.e. you will need to run a for each loop on it to get individual ids even with a single item:
On a side note: For future reference, if you run into C# anonymous type "var" in examples, the equivalent in vb is plain dim like in my query above (without the 'as type' part).
Hope this helps.
Maverik
使用 XPath 可以让大家省去麻烦吗?
Use XPath and save everyone the headaches?
如果您不介意使用 XDocument 以外的其他东西,我只会使用 XmlDocument:
从性能角度来看,这可能很糟糕。您还可以在字段上进行循环,然后在名称属性上使用开关,这样您就不会多次检查同一字段。无论如何,为什么你需要任何 linq 呢?
If you don't mind using something else than XDocument i'd just use a XmlDocument:
Performance-wise this might be abysmal. You could also have a loop on the Fields and then use a switch on the Name-Attribute so you don't check the same field more than once. Why would you need any linq for this anyway?
您的 linq 查询返回文档中的所有 Item 元素:
下面的代码尝试从 'Item' 元素获取 'ID' 属性:
但是,'ID' 属性位于 'Field' 子元素上。
您需要的是以下内容:
Your linq query returns all the Item elements in the document:
The code that follows is trying to obtain an 'ID' attribute from the 'Item' element:
However, the 'ID' attribute is on a 'Field' child element.
What you need is the following:
一个简单的解决方案是
它可以轻松转换为 vb 代码。
A Simple solution is
It can be easily converted in to vb code.
这是一个通用解决方案,可处理多个项目中具有不同字段名称的所有字段。它将结果保存在一张表中,其中包含所有不同的字段名称作为列名称。
我尝试尽可能多地使用 Linq,但 Linq 在递归处理嵌套元素时有点不灵活。
这是我使用的示例 xml 文件:
结果:
Here is a generic solution that handles all fields with different field names in several items. It saves the result in one table containing all distinct field names as column names.
I tried to use as much Linq as possible, but Linq is a bit inflexible when it comes to handling nested elements recursively.
Heres the sample xml file I've used:
And the result:
经过进一步的研究并在所提供答案的部分帮助下,我提出了以下内容,它返回了我想要的信息。
如果可以以任何方式改进以实现更好的性能,请告诉我。
感谢大家的帮助,虽然没有一个答案能够完全解决问题,但通过大家的帮助,我能够学到很多有关 Linq 的知识。
马特
After some further research and with the assistance of parts from the answers provided, I have come up with the following, which returns the information that I am after.
If this can be improved in any way to enable better performance, please let me know.
Thank you all for your assistance, while no one answer was able to entirely solve the problem I was able to learn a great deal about Linq through everyones assistance.
Matt
我希望您期待这样的简短答案,而不是另一个实现:
好的,到目前为止,应该不会遇到任何麻烦。变量名“name”有点混乱,所以我将其更改为“items”。
第二部分包含错误:
以下内容有效,因为有一个名为 Name 的属性,尽管结果是“ID”,这显然不是预期的:
这里出现错误:
c is the XmlNode '<<项目> ...< /项目>'并且它没有任何属性,因此 c.Attribute("ID") 的结果为 null。
我猜你想要类似下面的东西:
I hope you expected something like this short answer and not another implementation:
Ok so far nothing should run into any trouble. The variable name 'name' was a bit confusing, so I changed it to 'items'.
The second part contains the error:
The following works because there is an Attribute called Name, although the result is 'ID' what shurely wasn't expected:
Here comes the error:
c is the XmlNode '< Item > ... < / Item >' and it does not have any attributes, thus the result of c.Attribute("ID") is null.
I guess you wanted something like the following:
您的代码中存在一些错误:
您应该获得 XName 等于
Field
而不是Item
的后代您所使用的属性称为
Name
,而不是ID
在每个 str1 的第一次迭代中,它将是“ID”,下一次迭代将是“Name”,等等。
总代码:
There are a few errors in your code:
You should get the Descendents that have the XName equal to
Field
instead of toItem
The attribute you are after is called
Name
, notID
At the first iteration of your for each str1 will be "ID", the next one it will be "Name", etc.
Total code:
还有另一种方法可以解决这个问题。将此 XML 转换为
DataSet
所需的格式,然后使用DataSet.ReadXml
加载它。如果您不了解 XSLT,这会很痛苦。但如果您使用 XML,了解 XSLT 确实很重要。您需要的 XSLT 非常简单。从 XSLT 身份转换开始。然后添加一个模板,将
Response
和Item
元素转换为DataSet
期望的格式:这会将您的 XML 更改为如下所示的文档 :像这样:
...您可以将其提供给
DataSet.ReadXml
。编辑:
我应该指出,因为除非您经常这样做,否则它并不明显,因此这样做的一个影响是您需要创建和填充
DataSet< 的 C# 代码量/code> 是最小的:
它也是可重用的。您可以使用此方法根据需要从尽可能多的不同可能的输入格式填充尽可能多的不同的
DataSet
;您只需要为每种格式编写一个转换即可。There's another way to fix this problem. Transform this XML into the format that the
DataSet
wants, and then load it usingDataSet.ReadXml
. This is something of a pain if you don't know XSLT. But it's really important to know XSLT if you work with XML.The XSLT you'd need is pretty simple. Start with the XSLT identity transform. Then add a template that transforms the
Response
andItem
elements into the format that theDataSet
expects:That will change your XML to a document that looks like this:
...and you can just feed that to
DataSet.ReadXml
.Edit:
I should point out, since it's not obvious unless you do this a lot, that one effect of this is that the amount of C# code that you need to create and populate the
DataSet
is minimal:It's also reusable. You can use this method to populate as many different
DataSet
s from as many different possible input formats as you need; you just need to write a transform for each format.