Forum: Ruby Xpath to attributes

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Ccfe7d097475a32dc3ff78d6fc42c852?d=identicon&s=25 List Recv (lstrecv)
on 2006-02-22 03:14
(Received via mailing list)
Is there anyway to do generic xpath's, for both elements and attributes
(ie //customer/phone/@type --> "home")?  REXML can do xpath to fetch
elements (rexml_element.text('//customer/phone')) but can't seem to use
xpath to find attributes.
A9b6a93b860020caf9d2d1d58c32478f?d=identicon&s=25 Ross Bamford (Guest)
on 2006-02-22 11:39
(Received via mailing list)
On Wed, 2006-02-22 at 10:33 +0900, listrecv@gmail.com wrote:
> Is there anyway to do generic xpath's, for both elements and attributes
> (ie //customer/phone/@type --> "home")?  REXML can do xpath to fetch
> elements (rexml_element.text('//customer/phone')) but can't seem to use
> xpath to find attributes.

	d = REXML::Document.new <<EOX
	  <customer>
	    <phone type='home'>0115</phone>
	    <phone type='mobi'>07807</phone>
	  </customer>
	EOX

	m = REXML::XPath.match(d, '//customer/phone[@type = "home"]')
 	p m.to_s
	# => <phone type='home'>0115</phone>
2ee1a7960cc761a6e92efb5000c0f2c9?d=identicon&s=25 William James (Guest)
on 2006-02-23 05:09
(Received via mailing list)
listrecv@gmail.com wrote:
> Is there anyway to do generic xpath's, for both elements and attributes
> (ie //customer/phone/@type --> "home")?  REXML can do xpath to fetch
> elements (rexml_element.text('//customer/phone')) but can't seem to use
> xpath to find attributes.

class Array; alias atr first; alias txt last  end
class String
  def xtag(s)
    scan( %r!
              < #{s}  (?: \s+ (  [^>]*  )  )? / >
              |
              < #{s}  (?: \s+ (  [^>]*  )  )? >
              ( .*? )  </ #{s} >
          !mx ).
      map{ |unpaired, attr, data|   h = { }
        attr = ( unpaired || attr )
        if attr
          attr.scan( %r!  ( \S+ ) = ( ["'] ) ( .*? ) \2  !x ){ |k,q,v|
            h[k] = v }
        end
        [ h, data ]
      }
  end
  def xpath(s)
    s.scan(%r! [^/"]+ (?: "[^"]*" )? !x).inject([[nil,self]]){|ary,str|
      if "@" == str[0,1]
        str =~ /@(.*?)="(.*)"/
        ary.select{|a,t| a[$1] == $2 }
      else
        return []  if [] == ary
        ary[0].txt.xtag(str)
      end
    }
  end
end


p DATA.read.xpath('customer/@loc="south"/phone/@type="mobi"')


__END__
<customer loc="north">
  <phone type='home'>0115</phone>
  <phone type='mobi'>07807</phone>
</customer>
<customer loc="south">
  <phone type='home'>0319</phone>
  <phone type='mobi'>09802</phone>
</customer>
Ccfe7d097475a32dc3ff78d6fc42c852?d=identicon&s=25 List Recv (lstrecv)
on 2006-02-24 17:05
(Received via mailing list)
Thanks.

But I'd like to just extract the attribute value via Xpath.

If my Xpath is correct, I could just do '//customer/phone/@type' to get
'home'.  Is there any way I can do this in Ruby?
2ee1a7960cc761a6e92efb5000c0f2c9?d=identicon&s=25 William James (Guest)
on 2006-02-25 21:34
(Received via mailing list)
listrecv@gmail.com wrote:
> Thanks.
>
> But I'd like to just extract the attribute value via Xpath.
>
> If my Xpath is correct, I could just do '//customer/phone/@type' to get
> 'home'.  Is there any way I can do this in Ruby?


p DATA.read.xchain('customer/@loc="south"/phone').first.atr['type']

__END__
<customer loc="north">
  <phone type='home'>0115</phone>
  <phone type='mobi'>07807</phone>
</customer>
<customer loc="south">
  <phone type='home'>0319</phone>
</customer>


The rest:

class Array; alias atr first; alias txt last  end
class String
  def xtag(s)
    result = []
    scan( %r!
              < #{s}  (?: \s+ (  [^>]*  )  )? / >
              |
              < #{s}  (?: \s+ (  [^>]*  )  )? >
              ( .*? )  </ #{s} >
          !mx )  \
      { |unpaired, attr, data|   h = { }
        attr = ( unpaired || attr )
        attr.scan( %r{  ( \S+ ) = ( ["'] ) ( .*? ) \2  }x ){ |k,q,v|
          h[k] = v }   if attr
        block_given? ? ( yield [ h, data ] ) : result << [ h, data ]
      }
    result
  end
  def xchain(s)
    s.scan(%r! [^/"]+ (?: "[^"]*" )? !x).inject([[nil,self]]){|ary,str|
      if "@" == str[0,1]
        str =~ /@(.*?)="(.*)"/
        ary.select{|a,t| a[$1] == $2 }
      else
        return []  if [] == ary
        ary[0].txt.xtag(str)
      end
    }
  end
end
This topic is locked and can not be replied to.