按节点值查找Xml节点

时间:2016-01-04 00:09:02

标签: c# asp.net xml

我创建了一个项目来阅读Amazon Product Advertising 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条记录。

到目前为止,我知道我可以将“Item(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的XML文件以及相应的“FormattedPrice”的正确方向的指示。

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

非常感谢,詹姆斯

编辑更新: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'节点会给我错误'多个根元素'。但删除'ItemLookupResponse'和'OperationRequest'会给我工作代码。

在完整的XML响应中使用我的改编'查询'(上面)给出了错误'对象引用没有设置为对象的实例。'

如果有人能指出我正确的方向在完整的XML上运行我的改编“查询”,并且克服了“未设置为对象实例的对象引用”错误,我将非常感激。

非常感谢,詹姆斯

3 个答案:

答案 0 :(得分:0)

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

sys.stdout.encoding

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

# coding: utf-8
x = u'à'

编辑 - 由于您省略了命名空间而出现的问题 - 请在msdn上查看LINQ to XML namespaces

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

另请参阅SO上的这个问题:XElement namespaces (How to?)

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

答案 1 :(得分:0)

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;参考

答案 2 :(得分:0)

我使用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();

有关工作示例,请参阅this fiddle