使用 Linq 解析 XML

发布于 2024-10-13 01:55:25 字数 1386 浏览 3 评论 0原文

我有以下 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

愛上了 2024-10-20 01:55:25

您可以使用 XPath:(

Dim data = From item In loaded.Descendants("Item")
           Select
             ID = item.XPathSelectElement("Field[@Name='ID']").Value,
             Name = item.XPathSelectElement("Field[@Name='Name']").Value,
             Path = item.XPathSelectElement("Field[@Name='Path']").Value,
             Type = item.XPathSelectElement("Field[@Name='Type']").Value

请务必导入 System.Xml.XPath 命名空间)

或者将其直接添加到 DataTable:

Dim dt As New DataTable()
dt.Columns.Add("ID")
dt.Columns.Add("Name")
dt.Columns.Add("Path")
dt.Columns.Add("Type")
For Each item In loaded.Descendants("Item")
  dt.Rows.Add(
    item.XPathSelectElement("Field[@Name='ID']").Value,
    item.XPathSelectElement("Field[@Name='Name']").Value,
    item.XPathSelectElement("Field[@Name='Path']").Value,
    item.XPathSelectElement("Field[@Name='Type']").Value
  )
Next

You can use XPath:

Dim data = From item In loaded.Descendants("Item")
           Select
             ID = item.XPathSelectElement("Field[@Name='ID']").Value,
             Name = item.XPathSelectElement("Field[@Name='Name']").Value,
             Path = item.XPathSelectElement("Field[@Name='Path']").Value,
             Type = item.XPathSelectElement("Field[@Name='Type']").Value

(Be sure to import the System.Xml.XPath namespace)

Or to add it directly to a DataTable:

Dim dt As New DataTable()
dt.Columns.Add("ID")
dt.Columns.Add("Name")
dt.Columns.Add("Path")
dt.Columns.Add("Type")
For Each item In loaded.Descendants("Item")
  dt.Rows.Add(
    item.XPathSelectElement("Field[@Name='ID']").Value,
    item.XPathSelectElement("Field[@Name='Name']").Value,
    item.XPathSelectElement("Field[@Name='Path']").Value,
    item.XPathSelectElement("Field[@Name='Type']").Value
  )
Next
南汐寒笙箫 2024-10-20 01:55:25

另一种使用匿名类型的解决方案:

        var doc = XDocument.Load("c:\\test");

        var list = doc.Root
         .Elements("Item")
         .Select(item =>
          new
          {
              Id = item.Elements("Field").Where(e => e.Attribute("Name").Value == "ID").Select(e => e.Value).FirstOrDefault(),
              Path = item.Elements("Field").Where(e => e.Attribute("Name").Value == "Path").Select(e => e.Value).FirstOrDefault(),
              Name = item.Elements("Field").Where(e => e.Attribute("Name").Value == "Name").Select(e => e.Value).FirstOrDefault(),
          })
         .ToArray();

        foreach (var item in list)
        {
            var id = item.Id;
            var name = item.Name;
        }

new 运算符内的丑陋表达式可以与下一个匿名函数缩短:

Func<XElement, string, string> getAttrValue = (node, attrName) =>
{
 return node.Elements("Field")
  .Where(e => e.Attribute("Name").Value == attrName)
  .Select(e => e.Value)
  .FirstOrDefault();
};

然后 new 运算符如下所示:

 new 
 { 
  Id = getAttrValue(item, "ID"), 
  Path = getAttrValue(item, "Path"),
  Name = getAttrValue(item, "Name"),
 }

Another one solution with anonymous types:

        var doc = XDocument.Load("c:\\test");

        var list = doc.Root
         .Elements("Item")
         .Select(item =>
          new
          {
              Id = item.Elements("Field").Where(e => e.Attribute("Name").Value == "ID").Select(e => e.Value).FirstOrDefault(),
              Path = item.Elements("Field").Where(e => e.Attribute("Name").Value == "Path").Select(e => e.Value).FirstOrDefault(),
              Name = item.Elements("Field").Where(e => e.Attribute("Name").Value == "Name").Select(e => e.Value).FirstOrDefault(),
          })
         .ToArray();

        foreach (var item in list)
        {
            var id = item.Id;
            var name = item.Name;
        }

Ugly expression inside new operator can be shorted with next anonymous function:

Func<XElement, string, string> getAttrValue = (node, attrName) =>
{
 return node.Elements("Field")
  .Where(e => e.Attribute("Name").Value == attrName)
  .Select(e => e.Value)
  .FirstOrDefault();
};

Then new operator looks like:

 new 
 { 
  Id = getAttrValue(item, "ID"), 
  Path = getAttrValue(item, "Path"),
  Name = getAttrValue(item, "Name"),
 }
梦中楼上月下 2024-10-20 01:55:25

这是我尝试解决您的问题。我只是注意到您希望使用尽可能多的 LINQ,因此我相应地构建了 LINQ 查询。请注意,结果类型(对于“ID”)将是 IEnumerable(),即您需要在其上运行 for every 循环来获取单独的 id,即使是单个项目:

Dim loaded As XDocument = XDocument.Load(uriString)

Dim IDs = From items In loaded.Descendants("Item") _
         Let fields = items.Descendants("Field") _
         From field In fields _
         Where field.Attribute("Name").Value = "ID" _
         Select field.Value

旁注:供将来参考,如果您遇到示例中的 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:

Dim loaded As XDocument = XDocument.Load(uriString)

Dim IDs = From items In loaded.Descendants("Item") _
         Let fields = items.Descendants("Field") _
         From field In fields _
         Where field.Attribute("Name").Value = "ID" _
         Select field.Value

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

尬尬 2024-10-20 01:55:25

使用 XPath 可以让大家省去麻烦吗?

XmlDocument xml = new XmlDocument();
xml.Load(xmlSource);

string id = xml.SelectSingleNode("/Response/Item/Field[@Name='ID']").InnerText;
string name = xml.SelectSingleNode("/Response/Item/Field[@Name='Name']").InnerText;
string path = xml.SelectSingleNode("/Response/Item/Field[@Name='Path']").InnerText;

Use XPath and save everyone the headaches?

XmlDocument xml = new XmlDocument();
xml.Load(xmlSource);

string id = xml.SelectSingleNode("/Response/Item/Field[@Name='ID']").InnerText;
string name = xml.SelectSingleNode("/Response/Item/Field[@Name='Name']").InnerText;
string path = xml.SelectSingleNode("/Response/Item/Field[@Name='Path']").InnerText;
顾北清歌寒 2024-10-20 01:55:25

我想要获取 ID、名称和路径的属性值。

如果您不介意使用 XDocument 以外的其他东西,我只会使用 XmlDocument:

        XmlDocument doc = new XmlDocument();
        doc.Load(new XmlTextReader("XData.xml"));
        XmlNodeList items = doc.GetElementsByTagName("Item");
        foreach (XmlElement item in items.Cast<XmlElement>())
        {
            XmlElement[] fields = item.GetElementsByTagName("Field").Cast<XmlElement>().ToArray();
            string id = (from s in fields where s.Attributes["Name"].InnerText == "ID" select s).First().InnerText;
            string name = (from s in fields where s.Attributes["Name"].InnerText == "Name" select s).First().InnerText;
            string path = (from s in fields where s.Attributes["Name"].InnerText == "Path" select s).First().InnerText;

            //Do stuff with data.
        }

从性能角度来看,这可能很糟糕。您还可以在字段上进行循环,然后在名称属性上使用开关,这样您就不会多次检查同一字段。无论如何,为什么你需要任何 linq 呢?


        XmlDocument doc = new XmlDocument();
        doc.Load(new XmlTextReader("XData.xml"));
        XmlNodeList items = doc.GetElementsByTagName("Item");
        foreach (XmlElement item in items.Cast<XmlElement>())
        {
            foreach (XmlNode field in item.GetElementsByTagName("Field"))
            {
                string name = field.Attributes["Name"].InnerText;
                switch (name)
                {
                    case "ID":
                        string id = field.InnerText;
                        //Do stuff with data.
                        break;
                    case "Path":
                        string path = field.InnerText;
                        //Do stuff with data.
                        break;
                    case "Name":
                        string name = field.InnerText;
                        //Do stuff with data.
                        break;
                    default:
                        break;
                }
            }
        }

I am wanting to get the attribute values for ID, Name, and Path.

If you don't mind using something else than XDocument i'd just use a XmlDocument:

        XmlDocument doc = new XmlDocument();
        doc.Load(new XmlTextReader("XData.xml"));
        XmlNodeList items = doc.GetElementsByTagName("Item");
        foreach (XmlElement item in items.Cast<XmlElement>())
        {
            XmlElement[] fields = item.GetElementsByTagName("Field").Cast<XmlElement>().ToArray();
            string id = (from s in fields where s.Attributes["Name"].InnerText == "ID" select s).First().InnerText;
            string name = (from s in fields where s.Attributes["Name"].InnerText == "Name" select s).First().InnerText;
            string path = (from s in fields where s.Attributes["Name"].InnerText == "Path" select s).First().InnerText;

            //Do stuff with data.
        }

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?


        XmlDocument doc = new XmlDocument();
        doc.Load(new XmlTextReader("XData.xml"));
        XmlNodeList items = doc.GetElementsByTagName("Item");
        foreach (XmlElement item in items.Cast<XmlElement>())
        {
            foreach (XmlNode field in item.GetElementsByTagName("Field"))
            {
                string name = field.Attributes["Name"].InnerText;
                switch (name)
                {
                    case "ID":
                        string id = field.InnerText;
                        //Do stuff with data.
                        break;
                    case "Path":
                        string path = field.InnerText;
                        //Do stuff with data.
                        break;
                    case "Name":
                        string name = field.InnerText;
                        //Do stuff with data.
                        break;
                    default:
                        break;
                }
            }
        }
兮子 2024-10-20 01:55:25

您的 linq 查询返回文档中的所有 Item 元素:

Dim name = From c In loaded.Descendants("Item") Select c

下面的代码尝试从 'Item' 元素获取 'ID' 属性:

Dim str1 = result.Attribute("ID").Value

但是,'ID' 属性位于 'Field' 子元素上。

您需要的是以下内容:

// find all the Item elements
var items = loaded.Descendants("Item");
foreach(var item in items)
{
  // find all the Field child elements
  var fields = item.Descendants("Field");

  // find the field element which has an ID attribute, and obtain the element value  
  string id = fields.Where(field => field.Attribute("ID")!=null)
                    .Single()
                    .Value;

  // etc ...
}

Your linq query returns all the Item elements in the document:

Dim name = From c In loaded.Descendants("Item") Select c

The code that follows is trying to obtain an 'ID' attribute from the 'Item' element:

Dim str1 = result.Attribute("ID").Value

However, the 'ID' attribute is on a 'Field' child element.

What you need is the following:

// find all the Item elements
var items = loaded.Descendants("Item");
foreach(var item in items)
{
  // find all the Field child elements
  var fields = item.Descendants("Field");

  // find the field element which has an ID attribute, and obtain the element value  
  string id = fields.Where(field => field.Attribute("ID")!=null)
                    .Single()
                    .Value;

  // etc ...
}
二智少女 2024-10-20 01:55:25

一个简单的解决方案是

        var result = doc.Root.Descendants(XName.Get("Item")).Select(x =>  x.Descendants(XName.Get("Field")));


        foreach (var v in result)
        {
            string id = v.Single(x => x.Attribute(XName.Get("Name")).Value == "ID").Value;

            string name = v.Single(x => x.Attribute(XName.Get("Name")).Value == "Name").Value;

            string path = v.Single(x => x.Attribute(XName.Get("Name")).Value == "Path").Value;

            string type = v.Single(x => x.Attribute(XName.Get("Name")).Value == "Type").Value;

        }

它可以轻松转换为 vb 代码。

A Simple solution is

        var result = doc.Root.Descendants(XName.Get("Item")).Select(x =>  x.Descendants(XName.Get("Field")));


        foreach (var v in result)
        {
            string id = v.Single(x => x.Attribute(XName.Get("Name")).Value == "ID").Value;

            string name = v.Single(x => x.Attribute(XName.Get("Name")).Value == "Name").Value;

            string path = v.Single(x => x.Attribute(XName.Get("Name")).Value == "Path").Value;

            string type = v.Single(x => x.Attribute(XName.Get("Name")).Value == "Type").Value;

        }

It can be easily converted in to vb code.

转身以后 2024-10-20 01:55:25

这是一个通用解决方案,可处理多个项目中具有不同字段名称的所有字段。它将结果保存在一张表中,其中包含所有不同的字段名称作为列名称。

Module Module1

Function createRow(ByVal table As DataTable, ByVal item As XElement) As DataRow
    Dim row As DataRow = table.NewRow

    Dim fields = item.Descendants("Field")
    For Each field In fields
        row.SetField(field.Attribute("Name").Value, field.Value)
    Next

    Return row

End Function


Sub Main()
    Dim doc = XDocument.Load("XMLFile1.xml")

    Dim items = doc.Descendants("Item")

    Dim columnNames = From attr In items.Descendants("Field").Attributes("Name") Select attr.Value

    Dim columns = From name In columnNames.Distinct() Select New DataColumn(name)

    Dim dataSet As DataSet = New DataSet()
    Dim table As DataTable = New DataTable()
    dataSet.Tables.Add(table)

    table.Columns.AddRange(columns.ToArray())

    Dim rows = From item In items Select createRow(table, item)

    For Each row In rows
        table.Rows.Add(row)
    Next

    ' TODO Handle Table
End Sub

End Module

我尝试尽可能多地使用 Linq,但 Linq 在递归处理嵌套元素时有点不灵活。

这是我使用的示例 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>
  <Item>
    <Field Name="ID">123</Field>
    <Field Name="Name">ABC</Field>
    <Field Name="RandomFieldName">Other Value</Field>
    <Field Name="Type">FooBar</Field>
  </Item>
</Response>

结果:

ID         Name     Path          Type        RandomFieldName

767147519  Music    Family\Music  Playlist

123        ABC                    FooBar      Other Value

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.

Module Module1

Function createRow(ByVal table As DataTable, ByVal item As XElement) As DataRow
    Dim row As DataRow = table.NewRow

    Dim fields = item.Descendants("Field")
    For Each field In fields
        row.SetField(field.Attribute("Name").Value, field.Value)
    Next

    Return row

End Function


Sub Main()
    Dim doc = XDocument.Load("XMLFile1.xml")

    Dim items = doc.Descendants("Item")

    Dim columnNames = From attr In items.Descendants("Field").Attributes("Name") Select attr.Value

    Dim columns = From name In columnNames.Distinct() Select New DataColumn(name)

    Dim dataSet As DataSet = New DataSet()
    Dim table As DataTable = New DataTable()
    dataSet.Tables.Add(table)

    table.Columns.AddRange(columns.ToArray())

    Dim rows = From item In items Select createRow(table, item)

    For Each row In rows
        table.Rows.Add(row)
    Next

    ' TODO Handle Table
End Sub

End Module

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:

<?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>
  <Item>
    <Field Name="ID">123</Field>
    <Field Name="Name">ABC</Field>
    <Field Name="RandomFieldName">Other Value</Field>
    <Field Name="Type">FooBar</Field>
  </Item>
</Response>

And the result:

ID         Name     Path          Type        RandomFieldName

767147519  Music    Family\Music  Playlist

123        ABC                    FooBar      Other Value
指尖微凉心微凉 2024-10-20 01:55:25

经过进一步的研究并在所提供答案的部分帮助下,我提出了以下内容,它返回了我想要的信息。

Dim Query = From items In loaded.Descendants("Item") _   
Let sID = ( From q In items.Descendants("Field") _       
Where q.Attribute("Name").Value = "ID" ) _ 
Let sName = ( From r In items.Descendants("Field") _       
Where r.Attribute("Name").Value = "Name" ) _ 
Let sPath = ( From s In items.Descendants("Field") _       
Where s.Attribute("Name").Value = "Path" ) _ 
Where (Ctype(sPath.Value,String) Like "Family\*") _
Select pId=sID.Value, pName=sName.Value, pPath = sPath.Value

如果可以以任何方式改进以实现更好的性能,请告诉我。

感谢大家的帮助,虽然没有一个答案能够完全解决问题,但通过大家的帮助,我能够学到很多有关 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.

Dim Query = From items In loaded.Descendants("Item") _   
Let sID = ( From q In items.Descendants("Field") _       
Where q.Attribute("Name").Value = "ID" ) _ 
Let sName = ( From r In items.Descendants("Field") _       
Where r.Attribute("Name").Value = "Name" ) _ 
Let sPath = ( From s In items.Descendants("Field") _       
Where s.Attribute("Name").Value = "Path" ) _ 
Where (Ctype(sPath.Value,String) Like "Family\*") _
Select pId=sID.Value, pName=sName.Value, pPath = sPath.Value

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

话少心凉 2024-10-20 01:55:25

我希望您期待这样的简短答案,而不是另一个实现:

Dim items = From c In loaded.Descendants("Item") Select c (...)

好的,到目前为止,应该不会遇到任何麻烦。变量名“name”有点混乱,所以我将其更改为“items”。

第二部分包含错误:

Dim items = (...) Select sID = c.Element("Field").Attribute("Name").Value, sName = c.Attribute("ID").Value.FirstOrDefault

以下内容有效,因为有一个名为 Name 的属性,尽管结果是“ID”,这显然不是预期的:

c.Element("Field").Attribute("Name").Value

这里出现错误:

c.Attribute("ID").Value.FirstOrDefault

c is the XmlNode '<<项目> ...< /项目>'并且它没有任何属性,因此 c.Attribute("ID") 的结果为 null。

我猜你想要类似下面的东西:

Dim loaded = XDocument.Load("XMLFile1.xml")
Dim items = From item In loaded.Descendants("Item") Select _
            sID = (From field In item.Descendants("Field") _
                   Where field.Attribute("Name") = "ID" _
                   Select field.Value).FirstOrDefault() _
            , _
            sName = (From field In item.Descendants("Field") _
                     Where field.Attribute("Name") = "Name" _
                     Select field.Value).FirstOrDefault()

I hope you expected something like this short answer and not another implementation:

Dim items = From c In loaded.Descendants("Item") Select c (...)

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:

Dim items = (...) Select sID = c.Element("Field").Attribute("Name").Value, sName = c.Attribute("ID").Value.FirstOrDefault

The following works because there is an Attribute called Name, although the result is 'ID' what shurely wasn't expected:

c.Element("Field").Attribute("Name").Value

Here comes the error:

c.Attribute("ID").Value.FirstOrDefault

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:

Dim loaded = XDocument.Load("XMLFile1.xml")
Dim items = From item In loaded.Descendants("Item") Select _
            sID = (From field In item.Descendants("Field") _
                   Where field.Attribute("Name") = "ID" _
                   Select field.Value).FirstOrDefault() _
            , _
            sName = (From field In item.Descendants("Field") _
                     Where field.Attribute("Name") = "Name" _
                     Select field.Value).FirstOrDefault()
东京女 2024-10-20 01:55:25

您的代码中存在一些错误:

您应该获得 XName 等于 Field 而不是 Item 的后代

Dim name = From c In loaded.Descendants("Field") Select c

您所使用的属性称为 Name,而不是ID

Dim str1 = result.Attribute("Name").Value

在每个 str1 的第一次迭代中,它将是“ID”,下一次迭代将是“Name”,等等。

总代码:

Dim loaded As XDocument = XDocument.Load(uriString)
Dim name = From c In loaded.Descendants("Field") Select c
For Each result In name
  Dim str1 = result.Attribute("Name").Value 'Returns "ID"
  Dim str2 = result.Value ' Returns "767147519"
Next

There are a few errors in your code:

You should get the Descendents that have the XName equal to Field instead of to Item

Dim name = From c In loaded.Descendants("Field") Select c

The attribute you are after is called Name, not ID

Dim str1 = result.Attribute("Name").Value

At the first iteration of your for each str1 will be "ID", the next one it will be "Name", etc.

Total code:

Dim loaded As XDocument = XDocument.Load(uriString)
Dim name = From c In loaded.Descendants("Field") Select c
For Each result In name
  Dim str1 = result.Attribute("Name").Value 'Returns "ID"
  Dim str2 = result.Value ' Returns "767147519"
Next
这样的小城市 2024-10-20 01:55:25

还有另一种方法可以解决这个问题。将此 XML 转换为 DataSet 所需的格式,然后使用 DataSet.ReadXml 加载它。如果您不了解 XSLT,这会很痛苦。但如果您使用 XML,了解 XSLT 确实很重要。

您需要的 XSLT 非常简单。从 XSLT 身份转换开始。然后添加一个模板,将 ResponseItem 元素转换为 DataSet 期望的格式:

<xsl:template match="Response">
   <MyDataSetName>
      <xsl:apply-templates select="Item"/>
   </MyDataSetName>
</xsl:template>

<xsl:template match="Item">
   <MyDataTableName>
      <xsl:apply-templates select="Field[@Name='ID' or @Name='Name' or @Name='Path']"/>
   </MyDataTableName>
</xsl:template>

<xsl:template match="Field">
   <xsl:element name="{@Name}">
      <xsl:value-of select="."/>
   </xsl:element>
</xsl:template>

这会将您的 XML 更改为如下所示的文档 :像这样:

<MyDataSetName>
  <MyDataTableName>
    <ID>767147519</ID> 
    <Name>Music</Name> 
    <Path>Family\Music</Path> 
  </MyDataTableName>
</MyDataSetName>

...您可以将其提供给DataSet.ReadXml

编辑:

我应该指出,因为除非您经常这样做,否则它并不明显,因此这样做的一个影响是您需要创建和填充 DataSet< 的 C# 代码量/code> 是最小的:

    private DataSet GetDataSet(string inputFilename, string transformFilename)
    {
        StringBuilder sb = new StringBuilder();
        using (XmlReader xr = XmlReader.Create(inputFilename))
        using (XmlWriter xw = XmlWriter.Create(new StringWriter(sb)))
        {
            XslCompiledTransform xslt = new XslCompiledTransform();
            xslt.Load(transformFilename);
            xslt.Transform(xr, xw);
        }
        using (StringReader sr = new StringReader(sb.ToString()))
        {
            DataSet ds = new DataSet();
            ds.ReadXml(sr);
            return ds;
        }
    }

它也是可重用的。您可以使用此方法根据需要从尽可能多的不同可能的输入格式填充尽可能多的不同的DataSet;您只需要为每种格式编写一个转换即可。

There's another way to fix this problem. Transform this XML into the format that the DataSet wants, and then load it using DataSet.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 and Item elements into the format that the DataSet expects:

<xsl:template match="Response">
   <MyDataSetName>
      <xsl:apply-templates select="Item"/>
   </MyDataSetName>
</xsl:template>

<xsl:template match="Item">
   <MyDataTableName>
      <xsl:apply-templates select="Field[@Name='ID' or @Name='Name' or @Name='Path']"/>
   </MyDataTableName>
</xsl:template>

<xsl:template match="Field">
   <xsl:element name="{@Name}">
      <xsl:value-of select="."/>
   </xsl:element>
</xsl:template>

That will change your XML to a document that looks like this:

<MyDataSetName>
  <MyDataTableName>
    <ID>767147519</ID> 
    <Name>Music</Name> 
    <Path>Family\Music</Path> 
  </MyDataTableName>
</MyDataSetName>

...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:

    private DataSet GetDataSet(string inputFilename, string transformFilename)
    {
        StringBuilder sb = new StringBuilder();
        using (XmlReader xr = XmlReader.Create(inputFilename))
        using (XmlWriter xw = XmlWriter.Create(new StringWriter(sb)))
        {
            XslCompiledTransform xslt = new XslCompiledTransform();
            xslt.Load(transformFilename);
            xslt.Transform(xr, xw);
        }
        using (StringReader sr = new StringReader(sb.ToString()))
        {
            DataSet ds = new DataSet();
            ds.ReadXml(sr);
            return ds;
        }
    }

It's also reusable. You can use this method to populate as many different DataSets from as many different possible input formats as you need; you just need to write a transform for each format.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文