使用LINQ查询XDocument,如何获取特定值?



我正在尝试重构以下内容 - 这有效,但是如果我开始在XML中获取更多元素,它将变得难以管理:

HttpResponseMessage response = await httpClient.GetAsync("https://uri/products.xml");
string responseAsString = await response.Content.ReadAsStringAsync();
List<Product> productList = new List<Product>();
XDocument xdocument = XDocument.Parse(responseAsString);
var products = xdocument.Descendants().Where(p => p.Name.LocalName == "item");
foreach(var product in products)
{
var thisProduct = new Product();
foreach (XElement el in product.Nodes())
{
if(el.Name.LocalName == "id")
{
thisProduct.SKU = el.Value.Replace("-master", "");
}
if (el.Name.LocalName == "availability")
{
thisProduct.Availability = el.Value == "in stock";
}
}
productList.Add(thisProduct);
}

给定以下 XML URL

<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns="http://base.google.com/ns/1.0" version="0">
<channel>
<title>Product Feed</title>
<link></link>
<description>Products</description>
<item>
<availability>in stock</availability>
<id>01234-master</id>
...
</item>
<item>
<availability>in stock</availability>
<id>abcde-master</id>
...
</item>
</channel>
</rss>

理想情况下,我想删除循环和 if 语句,并有一个 LINQ 查询,该查询以干净的方式仅从 XML 返回我需要的字段(id、可用性等(,并用这些数据填充一个简单的类。

谁能帮忙?

有时你必须为你编写的代码感到高兴。有时没有"更聪明"的方法来写它......你只能写得"更好"一点:

List<Product> productList = new List<Product>();
XDocument xdocument = XDocument.Parse(responseAsString);
XNamespace ns = "http://base.google.com/ns/1.0";
var products = from x in xdocument.Elements(ns + "rss")
from y in x.Elements(ns + "channel")
from z in y.Elements(ns + "item")
select z;
foreach (var product in products)
{
var prod = new Product();
productList.Add(prod);
foreach (XElement el in product.Elements())
{
if (el.Name == ns + "id")
{
prod.SKU = el.Value.Replace("-master", string.Empty);
}
else if (el.Name == ns + "availability")
{
prod.Availability = el.Value == "in stock";
}
}
}

笔记:

  • 这种Descendants()在道德上是错误的。item的位置有一个固定的位置,/rss/channel/item,你非常清楚。这不是//item.因为明天可能会有今天不存在的rss/foo/item。您尝试编写代码,以便它与可以添加到 xml 的其他信息向前兼容。
  • 我确实讨厌 xml 命名空间...并且有具有多个嵌套命名空间的 xml。我多么讨厌这些。但是比我聪明的人决定它们存在。我接受。我使用它们编写代码。在LINQ-to-XML中,这很容易。有一个XNamespace甚至有一个超载的+运算符。

    请注意,如果你是一个微优化器(我尽量不做,但我不得不承认,但我的手有点痒(,你可以预先计算for周期内使用的各种ns + "xxx",因为从这里不清楚,但它们都是每个周期重建的。一个XName是如何在里面建造的...哦。。。这是一件令人着迷的事情,相信我。

    private static readonly XNamespace googleNs = "http://base.google.com/ns/1.0";
    private static readonly XName idName = googleNs + "id";
    private static readonly XName availabilityName = googleNs + "availability";
    

    然后

    if (el.Name == idName)
    {
    prod.SKU = el.Value.Replace("-master", string.Empty);
    }
    else if (el.Name == availabilityName)
    {
    prod.Availability = el.Value == "in stock";
    }
    

尝试以下操作:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:temptest.xml";
static void Main(string[] args)
{
new Item(FILENAME);
}
}
public class Item
{
public static List<Item> items { get; set; }
public string availability { get; set; }
public string id { get; set; }
public Item() { }
public Item(string filename)
{
string xml = File.ReadAllText(filename);
XDocument doc = XDocument.Parse(xml);
XElement root = doc.Root;
XNamespace ns = root.GetDefaultNamespace();
Item.items = doc.Descendants(ns + "item").Select(x => new Item() {
availability = (string)x.Element(ns + "availability"),
id = (string)x.Element(ns + "id")
}).ToList();
}
}
}

最新更新