croceldon
croceldon

Reputation: 4615

Retrieving XML namespace with Nokogiri

I'm using the code below to retreive the content of the ns2:Title tag from the XML shown below.

What I have so far:

results = Nokogiri::XML(search_results)
p results.xpath '//ns2:Title', 'ns2': 'http://mws.amazonservices.com/schema/Products/2011-10-01/default.xsd'

It works, but I don't like having to mention the ns2 namespace URL explicitly when it's already in the XML document. But I can't seem to retrieve it from the Products tag. I've tried variants of p results.css('Products').attr('xmlns:n2') but I can't get that work work, it just returns nil. How can I get the xmlns:n2 attribute value of the Products tag?

My (simplified for brevity) XML:

<?xml version="1.0"?>
<GetMatchingProductForIdResponse xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01">
  <GetMatchingProductForIdResult Id="028023810000" IdType="UPC" status="Success">
    <Products xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01" xmlns:ns2="http://mws.amazonservices.com/schema/Products/2011-10-01/default.xsd">
      <Product>
        <AttributeSets>
          <ns2:ItemAttributes xml:lang="en-US">
            <ns2:Studio>WECO Electrical Connectors Inc</ns2:Studio>
            <ns2:Title>Weco Wonder Shell Natural Minerals (3 Pack), Small</ns2:Title>
          </ns2:ItemAttributes>
        </AttributeSets>
        <Relationships>
          <VariationParent>
            <Identifiers>
              <MarketplaceASIN>
                <MarketplaceId>ATVPDKIKX0DER</MarketplaceId>
                <ASIN>B077HQHBQ6</ASIN>
              </MarketplaceASIN>
            </Identifiers>
          </VariationParent>
        </Relationships>
        <SalesRankings>
          <SalesRank>
            <ProductCategoryId>pet_products_display_on_website</ProductCategoryId>
            <Rank>14863</Rank>
          </SalesRank>
        </SalesRankings>
      </Product>
    </Products>
  </GetMatchingProductForIdResult>
</GetMatchingProductForIdResponse>

Upvotes: 0

Views: 628

Answers (1)

engineersmnky
engineersmnky

Reputation: 29598

css and xpath will return a NodeSet (think Enumerable#select) but you want the actual Element itself.

For this nokogiri provides the at_ prefixed methods, at_css and at_xpath, which will return the first matching Element. The implementation is very simple

css(*args).first 

So in order to get the namespace you are looking for either of the following will work and the are both identical in nature

 results.css('Products').first.namespaces['xmlns:ns2']
 #=> "http://mws.amazonservices.com/schema/Products/2011-10-01/default.xsd"
 results.at_css('Products').namespaces['xmlns:ns2']
 #=> "http://mws.amazonservices.com/schema/Products/2011-10-01/default.xsd"

However if your only target is the "ns2:Title" Elements then

results.xpath("//*[name() = 'ns2:Title']").text
#=> "Weco Wonder Shell Natural Minerals (3 Pack), Small"

Additionally if you just want any "Title" attributes and the name space is not necessary important then

results.xpath("//*[local-name() ='Title']").text
#=> "Weco Wonder Shell Natural Minerals (3 Pack), Small"

Upvotes: 1

Related Questions