按节点值查找Xml节点

本文关键字:节点 Xml 查找 | 更新日期: 2023-09-27 18:28:46

我创建了一个项目来阅读亚马逊产品广告API,使用以下代码检索XML文档:

WebRequest request = HttpWebRequest.Create(signedurl);
WebResponse responseStream = request.GetResponse();
XmlDocument doc = new XmlDocument();
doc.Load(responseStream.GetResponseStream());

而且,通过进一步的研究,我已经能够使用以下内容访问元素值;

XmlNode Item_IdNode = doc.GetElementsByTagName("ASIN").Item(0);
XmlNode PriceNode = doc.GetElementsByTagName("FormattedPrice").Item(3);
string F_Price = PriceNode.InnerText;
string xml_ItemId = Item_IdNode.InnerText;

此代码适用于访问产品ASIN和单个记录的价格,但我希望每个请求最多检索10条记录。

到目前为止,我知道我可以增加"项目(0)"来浏览其他项目ASIN,但"FormattedPrice"元素在每个产品中重复多次,对于其他产品记录,可能不一定出现在第6,9,12点。

对于检索到的每10条记录,我已经知道(使用)api调用中的ASIN(唯一产品参考)来选择特定的记录。

我想将代码推进到的地方是"搜索"物品ASIN"12345"的XML响应,然后深入到特定节点"OfferSummary/LowestNewPrice/FormattedPrice",将物品价格检索到变量中,依此类推,以查找所有其他ASIN的物品价格。

以下是前两个XML项记录的摘录(如果有帮助的话)。

    <Items>
      <Request>
      <IsValid>True</IsValid>
      <ItemLookupRequest>
            <Item><ASIN>12345</ASIN>
                  <OfferSummary>
                            <LowestNewPrice>
                            <Amount>1098</Amount>
                            <CurrencyCode>GBP</CurrencyCode>
                            <FormattedPrice>£10.98</FormattedPrice>
                            </LowestNewPrice>
                   </OfferSummary>
                   .
                   .
                   .
                   .
    <Items>
      <Request>
      <IsValid>True</IsValid>
      <ItemLookupRequest>
            <Item><ASIN>23456</ASIN>
                  <OfferSummary>
                            <LowestNewPrice>
                            <Amount>1098</Amount>
                            <CurrencyCode>GBP</CurrencyCode>
                            <FormattedPrice>£10.98</FormattedPrice>
                            </LowestNewPrice>
                   </OfferSummary>
                   .
                   .
                   .
                   .

我有一些asp.net的经验,但以前没有使用过XML"阅读器",如果能为每个ASIN及其相应的"FormattedPrice"在XML文件中"搜索"正确的方向,我将不胜感激。

希望这是足够的信息,如果需要任何进一步的信息,请告诉我。

非常感谢,James

编辑更新:2016年1月11日

非常感谢大家的回复,我一直在努力将您的回复纳入我的代码中的一个工作样本中(上周,我试图自己弄清楚)。尽管经过许多天的尝试,我仍然没有得到最终的工作解决方案。

我已将我的"查询"调整如下:

var res = XElement.Load(Server.MapPath("/App_Data/AWSS.xml"))
.Descendants("ASIN").FirstOrDefault(elem => elem.Value == "B001MS70F2")
.Parent.Descendants("FormattedPrice").Select(elem => elem.Value)
.FirstOrDefault();
Response.Write(res);

这在一定程度上是可行的,但在我最初的帖子中,我只发布了完整XML数据的摘录。上面的代码适用于我提供的示例XML,但不适用于包括我认为是"根"的完整数据。如果我删除了"ItemLookupResponse"节点(并请求死者),代码可以工作,但不适用于以下完整的XML数据;

<ItemLookupResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
<OperationRequest>
<HTTPHeaders>
<Header Name="UserAgent" Value="Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"/>
</HTTPHeaders>
<RequestId>#############</RequestId>
<Arguments>
<Argument Name="AWSAccessKeyId" Value="#############"/>
<Argument Name="AssociateTag" Value="#############"/>
<Argument Name="IdType" Value="ASIN"/>
<Argument Name="ItemId" Value="B001MS70F2,B007W1RSZA"/>
<Argument Name="Operation" Value="ItemLookup"/>
<Argument Name="ResponseGroup" Value="Offers"/>
<Argument Name="Service" Value="AWSECommerceService"/>
<Argument Name="Timestamp" Value="2016-01-06T23:01:02Z"/>
<Argument Name="Signature" Value="#############"/>
</Arguments>
<RequestProcessingTime>0.0209750000000000</RequestProcessingTime>
</OperationRequest>
<Items>
<Request>
<IsValid>True</IsValid>
<ItemLookupRequest>
<IdType>ASIN</IdType>
<ItemId>B001MS70F2</ItemId>
<ItemId>B007W1RSZA</ItemId>
<ResponseGroup>Offers</ResponseGroup>
<VariationPage>All</VariationPage>
</ItemLookupRequest>
</Request>
<Item>
<ASIN>B001MS70F2</ASIN>
<ParentASIN>B019IGAHUY</ParentASIN>
<OfferSummary>
<LowestNewPrice>
<Amount>1049</Amount>
<CurrencyCode>GBP</CurrencyCode>
<FormattedPrice>£10.49</FormattedPrice>
</LowestNewPrice>
<TotalNew>32</TotalNew>
<TotalUsed>0</TotalUsed>
<TotalCollectible>0</TotalCollectible>
<TotalRefurbished>0</TotalRefurbished>
</OfferSummary>
<Offers>
<TotalOffers>1</TotalOffers>
<TotalOfferPages>1</TotalOfferPages>
<MoreOffersUrl>
http://www.amazon.co.uk/gp/offer-listing/B001MS70F2%3FSubscriptionId%3DAKIAI4V5X2Q7F3BOU7MA%26tag%3Dbusin02-21%26linkCode%3Dxm2%26camp%3D2025%26creative%3D12734%26creativeASIN%3DB001MS70F2
</MoreOffersUrl>
<Offer>
<OfferAttributes>
<Condition>New</Condition>
</OfferAttributes>
<OfferListing>
<OfferListingId>
VbyiDUr1A7VXNun65VvEF8WmWG3ZOzirk%2BGjIdOOGBB38lLlcRYaEKyl4pS6hdrqhZuOLqfW4uTVLtqsCUfanWyEaltghotq
</OfferListingId>
<Price>
<Amount>1049</Amount>
<CurrencyCode>GBP</CurrencyCode>
<FormattedPrice>£10.49</FormattedPrice>
</Price>
<AmountSaved>
<Amount>284</Amount>
<CurrencyCode>GBP</CurrencyCode>
<FormattedPrice>£2.84</FormattedPrice>
</AmountSaved>
<PercentageSaved>21</PercentageSaved>
<Availability>Usually dispatched within 24 hours</Availability>
<AvailabilityAttributes>
<AvailabilityType>now</AvailabilityType>
<MinimumHours>0</MinimumHours>
<MaximumHours>0</MaximumHours>
</AvailabilityAttributes>
<IsEligibleForSuperSaverShipping>1</IsEligibleForSuperSaverShipping>
<IsEligibleForPrime>1</IsEligibleForPrime>
</OfferListing>
</Offer>
</Offers>
</Item>
<Item>
<ASIN>B007W1RSZA</ASIN>
<OfferSummary>
<LowestNewPrice>
<Amount>1630</Amount>
<CurrencyCode>GBP</CurrencyCode>
<FormattedPrice>£16.30</FormattedPrice>
</LowestNewPrice>
<TotalNew>7</TotalNew>
<TotalUsed>0</TotalUsed>
<TotalCollectible>0</TotalCollectible>
<TotalRefurbished>0</TotalRefurbished>
</OfferSummary>
<Offers>
<TotalOffers>1</TotalOffers>
<TotalOfferPages>1</TotalOfferPages>
<MoreOffersUrl>
http://www.amazon.co.uk/gp/offer-listing/B007W1RSZA%3FSubscriptionId%3DAKIAI4V5X2Q7F3BOU7MA%26tag%3Dbusin02-21%26linkCode%3Dxm2%26camp%3D2025%26creative%3D12734%26creativeASIN%3DB007W1RSZA
</MoreOffersUrl>
<Offer>
<OfferAttributes>
<Condition>New</Condition>
</OfferAttributes>
<OfferListing>
<OfferListingId>
VbyiDUr1A7VXNun65VvEF74FLb5xO3BqKAr7e2DBjtDJNt3ZXQTDuPuGzaLdifzl2xEs1x4swNRE3U6yP3JfXvjWXxBDUM1vGxR8eaR1suappuRh5ZARKbjoGHx3NvEpVdrLfxvwmIzXoFSSq50uWg%3D%3D
</OfferListingId>
<Price>
<Amount>1630</Amount>
<CurrencyCode>GBP</CurrencyCode>
<FormattedPrice>£16.30</FormattedPrice>
</Price>
<Availability>Usually dispatched within 1-2 business days</Availability>
<AvailabilityAttributes>
<AvailabilityType>now</AvailabilityType>
<MinimumHours>24</MinimumHours>
<MaximumHours>48</MaximumHours>
</AvailabilityAttributes>
<IsEligibleForSuperSaverShipping>0</IsEligibleForSuperSaverShipping>
<IsEligibleForPrime>0</IsEligibleForPrime>
</OfferListing>
</Offer>
</Offers>
</Item>
</Items>
</ItemLookupResponse>

我尝试了许多代码排列,这让我得出结论,删除"ItemLookupResponse"节点会导致错误"multiple root elements"。但是删除"ItemLookupResponse"answers"OperationRequest"会给我提供工作代码。

在完整的XML响应上使用我调整后的"query"(如上)会出现错误"Object reference not set to a instance of a Object"

如果有人能为我指明正确的方向,让我在完整的XML上运行经过调整的"查询",并克服"对象引用未设置为对象实例"的错误,我将不胜感激。

非常感谢,James

按节点值查找Xml节点

您可以使用LINQ to XML-这将返回给定ASIN值的格式化价格:

var res = XElement.Parse("data.xml")
                  .Descendants("ASIN").FirstOrDefault(elem => elem.Value == "12345")
                  .Parent.Descendants("FormattedPrice").Select(elem => elem.Value)
                  .FirstOrDefault();

如果您想在文档中获取所有ASIN:

var asins = XElement.Parse("data.xml")
                    .Descendants("ASIN")
                    .Select(elem => elem.Value)
                    .ToList();

编辑-由于省略了名称空间而出现的问题-请检查msdn上的LINQ to XML名称空间。

XNamespace ns = "http://webservices.amazon.com/AWSECommerceService/2011-08-01";
var res = XElement.Load("data.xml")
                  .Descendants(ns+ "ASIN").FirstOrDefault(elem => elem.Value == "B001MS70F2")
                  .Parent.Descendants(ns + "FormattedPrice").Select(elem => elem.Value)
                  .FirstOrDefault();
Console.WriteLine(res);    // prints L10.49  

还可以看看这个关于SO:XElement命名空间的问题(如何?)

在msdn上:https://msdn.microsoft.com/en-us/library/system.xml.linq.xnamespace(v=vs.110).aspx

static void Main(string[] args)
        {
            string xml = @"<ParentNode>
    <Items>
        <Request>
            <IsValid>True</IsValid>
            <ItemLookupRequest>
            <Item>
                <ASIN>B001MS70F1</ASIN>
                <OfferSummary>
                        <LowestNewPrice>
                            <Amount>1098</Amount>
                            <CurrencyCode>GBP</CurrencyCode>
                            <FormattedPrice>£15.98</FormattedPrice>
                        </LowestNewPrice>
                </OfferSummary>
            </Item>
            </ItemLookupRequest>
        </Request>
    </Items>
    <Items>
        <Request>
            <IsValid>True</IsValid>
            <ItemLookupRequest>
                <Item>
                    <ASIN>B001MS70212</ASIN>
                    <OfferSummary>
                            <LowestNewPrice>
                                <Amount>1098</Amount>
                                <CurrencyCode>GBP</CurrencyCode>
                                <FormattedPrice>£10.98</FormattedPrice>
                            </LowestNewPrice>
                    </OfferSummary>
                </Item>
            </ItemLookupRequest>
        </Request>
    </Items>
    </ParentNode>";
            XDocument doc = XDocument.Parse(xml);
            List<XElement> elements = doc.Descendants("Item").ToList();
            foreach(XElement elem in elements)
            {
                string asin = elem.Element("ASIN").Value;
                string formatedPrice = elem.Element("OfferSummary").Element("LowestNewPrice").Element("FormattedPrice").Value;
//you can use this for formated price too
                string formatedPrice2 = elem.Descendants("FormattedPrice").FirstOrDefault().Value;
                Console.WriteLine("ASIN: " + asin + " and Price:" + formatedPrice);
            }
            Console.ReadKey();
        }

下面是一个示例程序,下次至少发布有效的xml。您需要添加using System.Xml.Linq;参考

我会使用LINQ to XML解析数据,然后创建这样的查询:

var prices = from item in doc.Descendants("Item")
             from summary in item.Elements("OfferSummary")
             from lowestNewPrice in summary.Elements("LowestNewPrice")
             select new
             {
                 ASIN = (string) item.Element("ASIN"),
                 FormattedPrice = (string) lowestNewPrice.Element("FormattedPrice")
             };

然后,您可以将其转换为字典,或者简单地查询您的ASIN:

var price = prices.Where(x => x.ASIN == "12345")
    .Select(x => x.FormattedPrice)
    .Single();

请参阅此小提琴以获取工作示例。