# Xpath to attributes

**URL:** <https://rubytalk.org/t/xpath-to-attributes/25130>\
**Category:** ruby-talk\
**Created:** [22 February 2006 01:33 UTC](https://rubytalk.org/t/xpath-to-attributes/25130 "2006-02-22T01:33:32Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![List\_Recv](https://avatars.discourse-cdn.com/v4/letter/l/dec6dc/32.png) [@List\_Recv](https://rubytalk.org/u/List_Recv)\
**Post date:** [22 February 2006 01:33 UTC](https://rubytalk.org/t/xpath-to-attributes/25130/1 "2006-02-22T01:33:32Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Ross\_Bamford4](https://avatars.discourse-cdn.com/v4/letter/r/ea666f/32.png) [@Ross\_Bamford4](https://rubytalk.org/u/Ross_Bamford4)\
**Post date:** [22 February 2006 10:36 UTC](https://rubytalk.org/t/xpath-to-attributes/25130/2 "2006-02-22T10:36:57Z")

</div>

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

&nbsp;&nbsp;m = REXML::XPath.match(d, '//customer/phone[@type = "home"]')  
&nbsp;&nbsp;&nbsp;p m.to\_s  
&nbsp;&nbsp;# =\> \<phone type='home'\>0115\</phone\>

> **···**
>
> 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.
> 
> --  
> Ross Bamford - rosco@roscopeco.REMOVE.co.uk

---

<div class="post-metadata">

**Author:** ![W\_James](https://avatars.discourse-cdn.com/v4/letter/w/e274bd/32.png) [@W\_James](https://rubytalk.org/u/W_James)\
**Post date:** [23 February 2006 04:08 UTC](https://rubytalk.org/t/xpath-to-attributes/25130/3 "2006-02-23T04:08:32Z")

</div>

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

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

\_\_END\_\_  
\<customer loc="north"\>  
&nbsp;&nbsp;\<phone type='home'\>0115\</phone\>  
&nbsp;&nbsp;\<phone type='mobi'\>07807\</phone\>  
\</customer\>  
\<customer loc="south"\>  
&nbsp;&nbsp;\<phone type='home'\>0319\</phone\>  
&nbsp;&nbsp;\<phone type='mobi'\>09802\</phone\>  
\</customer\>

---

<div class="post-metadata">

**Author:** ![List\_Recv](https://avatars.discourse-cdn.com/v4/letter/l/dec6dc/32.png) [@List\_Recv](https://rubytalk.org/u/List_Recv)\
**Post date:** [24 February 2006 16:03 UTC](https://rubytalk.org/t/xpath-to-attributes/25130/4 "2006-02-24T16:03:32Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![W\_James](https://avatars.discourse-cdn.com/v4/letter/w/e274bd/32.png) [@W\_James](https://rubytalk.org/u/W_James)\
**Post date:** [25 February 2006 20:33 UTC](https://rubytalk.org/t/xpath-to-attributes/25130/5 "2006-02-25T20:33:33Z")

</div>

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"\>  
&nbsp;&nbsp;\<phone type='home'\>0115\</phone\>  
&nbsp;&nbsp;\<phone type='mobi'\>07807\</phone\>  
\</customer\>  
\<customer loc="south"\>  
&nbsp;&nbsp;\<phone type='home'\>0319\</phone\>  
\</customer\>

The rest:

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