2016-01-04 2 views
1

Я создал проект для чтения Amazon рекламы продукта API, извлекая документ XML, используя следующий код:Найти 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 зачисленных записей я уже знаю (используйте) ASIN (уникальная ссылка на продукт) в вызове api для выбора конкретных записей.

Где я хотел бы продвигать код, чтобы «искать» ответ XML для элемента ASIN «12345», затем перейти к конкретному узлу «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 «читатели» и был бы признателен за любые указатели в правильном направлении на «Поиск» файла XML для каждого ASIN, и его соответствующей «FormattedPrice».

Надеюсь, что это достаточная информация, пожалуйста, дайте мне знать, если потребуется какая-либо дополнительная информация.

Большое спасибо, Джеймс

EDITED UPDATE: 11 января 2016

Большое спасибо за ответы каждого, я работал, чтобы включить ваши ответы в рабочий образец в моем коде (за последнюю неделю , пытаясь понять это для себя). Хотя после многих дней для попытки у меня все еще нет окончательного рабочего решения.

Я адаптировал свой «запрос» следующим образом:

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, который я предоставил, но не для полных данных, которые включают в себя то, что я считаю «root». Если я удалю узел «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 и преодолеть ошибку «Ссылка на объект, не установленную на экземпляр объекта».

Большое спасибо, Джеймс

+1

Вы можете использовать ['XElement'] (https://msdn.microsoft.com/en-us/library/system.xml.linq.xelement (v = vs.110) .aspx) класс или [' XDocument '] (https://msdn.microsoft.com/en-us/library/system.xml.linq.xdocument (v = vs.110) .aspx) и найти itenm с помощью linq –

ответ

0

Вы можете использовать LINQ для XML - это вернет форматированный цену для заданного значения ASIN:

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

Если вы хотите, чтобы получить все ASINs в документе:

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

Редактировать - проблема возникает из-за того, что вы пропускаете пространства имен - проверьте LINQ to XML namespaces на msdn.

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 namespaces (How to?)

и это на MSDN: https://msdn.microsoft.com/en-us/library/system.xml.linq.xnamespace(v=vs.110).aspx

+0

Привет wb - Я очень благодарю вас за то, что вы нашли время ответить на мой пост. Я добавил поправку к первоначальному сообщению. Просто интересно, можно ли изменить решение, которое вы предоставили, для решения проблемы, описанной в моем отредактированном сообщении. С наилучшими пожеланиями, Джеймс – James

+0

@ Джеймс - только что обновлено. –

+0

Удивительный! Отличный материал, спасибо за ваш ответ - с вашей помощью я наконец получил свой код. Большое спасибо за поддержку других «плакатов». Всего наилучшего, Джеймс – James

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; присвоенный

0

Я бы разобрать данные с помощью LINQ к 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 для рабочего примера.

Смежные вопросы