Never been to DZone Snippets before?
Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world
Adding helpful error messages to your Ruby code
1 2 def map_pattr(node, fieldx, valuex) 3 begin 4 parameter = node.root.elements["parameter[@field='#{fieldx}']"] 5 parameter.add_attribute('value', valuex) 6 parameter 7 8 rescue 9 puts 'feedpopulated.rb: map_attr() the field ' + fieldx + ' was not found in params.' 10 raise 11 end 12 end
Notice that a raise statement is used to ensure that the system error message is raised and any further code execution is halted.
Without adding a customized helpful message I would be left scratching my head trying to work out what the following system error message meant.
1 2 ./feedpopulated.rb:27:in `map_pattr': undefined method `add_attribute' for nil:NilClass (NoMethodError) 3 from ./feedpopulated.rb:51:in `create_record' 4 from ./feedpopulated.rb:49:in `each' 5 from ./feedpopulated.rb:49:in `create_record' 6 from ./recordx.rb:91:in `call_create' 7 from ./s3fileuploader_handler.rb:14:in `call' 8 from ./s3fileuploader_handler.rb:40:in `invoke' 9 from ./uploadtwitteraudio.rb:22:in `initialize' 10 from /usr/lib/ruby/1.8/rexml/element.rb:890:in `each' 11 from /usr/lib/ruby/1.8/rexml/xpath.rb:53:in `each' 12 from /usr/lib/ruby/1.8/rexml/element.rb:890:in `each' 13 from ./uploadtwitteraudio.rb:18:in `initialize' 14 from ./uploadtwitteraudio.rb:72:in `new' 15 from ./uploadtwitteraudio.rb:72
Reference: Programming Ruby: The Pragmatic Programmer's Guide - Exceptions, Catch, and Throw [ruby-doc.org]
Helpful XPath examples
Predicates
1 2 /bookstore/book[1] # Selects the first book element that is the child of the bookstore element. 3 # Note: IE5 and later has implemented that [0] should be the first node, 4 # but according to the W3C standard it should have been [1]!! 5 /bookstore/book[last()] # Selects the last book element that is the child of the bookstore element 6 /bookstore/book[last()-1] # Selects the last but one book element that is the child of the bookstore element 7 /bookstore/book[position()<3] # Selects the first two book elements that are children of the bookstore element 8 //title[@lang] # Selects all the title elements that have an attribute named lang
Selecting Unknown Nodes
1 2 /bookstore/* # Selects all the child nodes of the bookstore element 3 //* # Selects all elements in the document 4 //title[@*] # Selects all title elements which have any attribute
Selecting Several Paths
1 2 //book/title | //book/price # Selects all the title AND price elements of all book elements
Deleting a redundant shape message from the whiteboard queue
1 2 def call_delete_shape(params) 3 #get the shape's message id. 4 doc = Document.new(params) 5 shape_id = doc.root.elements["param[@var='id']"].text.to_s 6 initialize_doc 7 8 doc_xml = Document.new(decode2(@doc_file.root.to_s)) 9 id = doc_xml.root.elements["records/message/body/*[@id='#{shape_id}']"].parent.parent.attributes.get_attribute('id') 10 delete_record(id) 11 save_file 12 end
*update 10:04pm*
Added the link to the project code http://github.com/jrobertson/whiteboardqueue/tree
Some simple javascript xpath examples
1 2 var canCElC = document.evaluate( '//a[@class="canc"]' ,document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); 3 4 for (var m = 0; m < canCElC.snapshotLength; m++){ 5 6 var im = canCElC.snapshotItem(m); 7 8 } 9 10 var mems = document.evaluate( '//a[contains(@href, "profile")][ not( @class = "skyblue" )]' ,document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); 11 12 for (var l = 0; l < mems.snapshotLength; l++){ 13 14 var cThis = mems.snapshotItem(l); 15 16 } 17 18 var canHazPics = document.evaluate( '//a[@title= "Click for large image"]' ,document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue; 19 20 document.evaluate( 'html/body/div/div[7]/table/tbody/tr[2]/td[ not( contains(@id, "main") )]' ,document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); 21 22 for(... 23 24 //bravo's xpath function shortcut 25 // if you don't have $x already 26 function $x(p, c) { 27 var i, r = [], x = document.evaluate(p, c || document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null); 28 while(i=x.iterateNext()) r.push(i); 29 return r; 30 } 31 // 32 // a function to change history days in links 33 // 34 // Usage: ChangeDays(n); where n is 1, 3, 7, 14, 30 or 60 - not sure what other values may do to poor Simones Site 35 // 36 function ChangeDays(d) { 37 $x('//a[contains(@href, "/forum-user.cfm?id=")][not(contains(@href, "days="))]').forEach(function(e) { 38 e.setAttribute('href', e.getAttribute('href').replace(/cfm\?id=/, 'cfm?days='+d+'&id=')); 39 }); 40 } 41 42 43 // more bravo stuff 44 45 // getById 46 function $i(id) { 47 return document.getElementById(id); 48 } 49 // xpath unordered nodes 50 function $xu(p, c) { 51 var i, r = [], x = document.evaluate(p, c || document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null); 52 while(i=x.iterateNext()) r.push(i); 53 return r; 54 } 55 // xpath ordered nodes 56 function $xo(p, c) { 57 var i, r = [], x = document.evaluate(p, c || document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null); 58 while(i=x.iterateNext()) r.push(i); 59 return r; 60 } 61 // xpath single first node 62 function $xf(p, c) { 63 return document.evaluate(p, c || document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; 64 } 65 // xpath single any node 66 function $xa(p, c) { 67 return document.evaluate(p, c || document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; 68 } 69 // getByCLASS(className, orderedFlag); 70 // untested!! 71 function $c(cls, o) { 72 var fn=$xu; 73 if(o) fn=$xo; 74 return fn('//*[@class = "'+cls+'"' + 75 ' or contains(@class, " '+cls+' ")' + 76 ' or starts-with(@class, "' +cls+' ")' + 77 ' or substring(@class,string-length(@class)-'+cls.length+')=" '+cls+'"]'); 78 } 79 // create Element 80 function $ec(type, attributes){ 81 var node = document.createElement(type); 82 for (var attr in attributes) if (attributes.hasOwnProperty(attr)){ 83 node.setAttribute(attr, attributes[attr]); 84 } 85 return node; 86 } 87 // delete Element 88 function $ed(element) { 89 element.parentNode.removeChild(element); 90 } 91 // insert element after 92 function $ea(newNode, node) { 93 return node.parentNode.insertBefore(newNode, node.nextSibling); 94 } 95 // insert element before 96 function $eb(newNode, node) { 97 return node.parentNode.insertBefore(newNode, node); 98 } 99 // make element first child of par 100 function $ef(newNode, par) { 101 return par.insertBefore(newNode, par.firstChild); 102 } 103 // make element last child of par 104 function $el(newNode, par) { 105 return par.appendChild(newNode); 106 } 107 108
Display a filtered list using XSLT
file: dir.xsl
1 2 <?xml version="1.0"?> 3 4 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 5 6 <xsl:template match="dir"> 7 <div id="articles"> 8 <ul> 9 <xsl:apply-templates select="records/file[@type='rb']"/> 10 </ul> 11 </div> 12 </xsl:template> 13 14 <xsl:template match="records/file[@type='rb']"> 15 <li><xsl:value-of select="."/></li> 16 </xsl:template> 17 18 </xsl:stylesheet>
output:
1 2 <div id='articles'> 3 <ul> 4 <li>projxmlhelper.rb</li> 5 <li>feedpopulated.rb</li> 6 <li>squrl_handler.rb</li> 7 <li>password_handler.rb</li> 8 <li>category.rb</li> 9 <li>gwd.rb</li> 10 </ul> 11 </div> 12
*update 11:58am 26-Feb*
Here's a filter I will be using in my projects
1 2 <?xml version="1.0"?> 3 4 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 5 6 <xsl:template match="dir"> 7 <div id="articles"> 8 <ul> 9 <xsl:apply-templates select="records/file"/> 10 </ul> 11 </div> 12 </xsl:template> 13 14 <xsl:template match="records/file"> 15 <xsl:if test="@type=$type"> 16 <li><xsl:value-of select="."/></li> 17 </xsl:if> 18 </xsl:template> 19 20 </xsl:stylesheet>
Using XPath in JavaScript (Mozilla based)
doc (xml document)
1 2 <codes> 3 <codex value='bQ' index='Q'/> 4 <codex value='S' index='R'/> 5 <codex value='PU' index='S'/> 6 <codex value='ji' index='T'/> 7 <codex value='0' index='U'/> 8 <codex value='33' index='V'/> 9 <codex value='A' index='W'/> 10 <codex value='tO' index='X'/> 11 <codex value='fW' index='Y'/> 12 <codex value='P' index='Z'/> 13 <codex value='4h' index='a'/> 14 <codex value='B' index='b'/> 15 <codex value='m' index='c'/> 16 <codex value='qf' index='d'/> 17 <codex value='uJ' index='e'/> 18 </codes>
Assuming the doc object below contains the XML data from above.
1 2 var nodesSnapshot = doc.evaluate("codes/codex[@index='a']", doc, null, XPathResult. 3 UNORDERED_NODE_SNAPSHOT_TYPE, null ); 4 node = nodesSnapshot.snapshotItem(0); 5 msg = "The secret code for '" + node.getAttribute('index') + "' is " + node.getAttribute('value'); 6 alert(msg);
output (value from the alert box)
1 2 "The secret code for 'a' is 4h"
see also: Reading an XML file using JavaScript
DOM Mouse-Over Element Selection and Isolation
bookmarklet for selecting and isolating an element on a page.
two sections:
section 1: Mouseover DOM, setup and handle mouse events and show information about element in informational div. Click to select, Any key to cancel.
section 2: Element Isolation with help of XPath. prompt user for XPath expression e.g., //DIV[@id='post-body']. then use XPath to select all elements not(ancestor or descendant or self), then delete those elements. also ignore self-or-descendants of head and title.
tools:
Ruderman's javascript development environment: https://www.squarefree.com/bookmarklets/webdevel.html#jsenv
Mielczarek's js to bookmarklet generator: http://ted.mielczarek.org/code/mozilla/bookmarklet.html
1 2 3 (function() { 4 //GLOBALS 5 //globals for classMausWork 6 var gSelectedElement; //currently only one selection 7 var gHoverElement; //whatever element the mouse is over 8 var gHovering=false; //mouse is over something 9 var gObjArrMW=[]; //global array of classMausWork objects. for removing event listeners when done selecting. 10 11 //extended 12 var infoDiv; //currently just container for InfoDivHover, might add more here 13 var infoDivHover; //container for hoverText text node. 14 var hoverText; //show information about current element that the mouse is over 15 //const EXPERIMENTAL_NEW_CODE=true; //debugging. new features. 16 17 18 //START 19 SetupDOMSelection(); 20 21 22 23 24 //(Section 1) Element Selection 25 function SetupDOMSelection() 26 { 27 28 { 29 //setup event listeners 30 //var pathx="//div | //span | //table | //td | //tr | //ul | //ol | //li | //p"; 31 var pathx="//div | //span | //table | //th | //td | //tr | //ul | //ol | //li | //p | //iframe"; 32 var selection=$XPathSelect(pathx); 33 for(var element, i=0;element=selection(i);i++) 34 { 35 if(element.tagName.match(/^(div|span|table|td|tr|ul|ol|li|p)$/i)) //redundant check. 36 { 37 var m = new classMausWork(element); 38 gObjArrMW.push(m); 39 attachMouseEventListeners(m); 40 } 41 } 42 document.body.addEventListener('mousedown',MiscEvent,false); 43 document.body.addEventListener('mouseover',MiscEvent,false); 44 document.body.addEventListener('mouseout',MiscEvent,false); 45 document.addEventListener('keypress',MiscEvent,false); 46 } 47 { 48 //setup informational div to show which element the mouse is over. 49 infoDiv=document.createElement('div'); 50 var s=infoDiv.style; 51 s.position='fixed'; 52 s.top='0'; 53 s.right='0'; 54 55 s.display='block'; 56 s.width='auto'; 57 s.padding='0px'; 58 59 document.body.appendChild(infoDiv); 60 infoDivHover=document.createElement('div'); 61 62 s=infoDivHover.style; 63 s.fontWeight='bold'; 64 s.padding='3px'; 65 s.Opacity='0.8'; 66 s.borderWidth='thin'; 67 s.borderStyle='solid'; 68 s.borderColor='white'; 69 s.backgroundColor='black'; 70 s.color='white'; 71 72 infoDiv.appendChild(infoDivHover); 73 hoverText=document.createTextNode('selecting'); 74 infoDivHover.appendChild(hoverText); 75 } 76 } 77 78 function CleanupDOMSelection() 79 { 80 for(var m; m=gObjArrMW.pop(); ) 81 { 82 detachMouseEventListeners(m); 83 } 84 ElementRemove(infoDiv); 85 document.body.removeEventListener('mousedown',MiscEvent,false); 86 document.body.removeEventListener('mouseover',MiscEvent,false); 87 document.body.removeEventListener('mouseout',MiscEvent,false); 88 document.removeEventListener('keypress',MiscEvent,false); 89 } 90 91 function attachMouseEventListeners(c) 92 { 93 //c is object of class classMausWork 94 c.element.addEventListener("mouseover",c.mouse_over,false); 95 c.element.addEventListener("mouseout",c.mouse_out,false); 96 c.element.addEventListener("mousedown",c.mouse_click,false); 97 } 98 99 function detachMouseEventListeners(c) 100 { 101 //c is object of class classMausWork 102 c.resetElementStyle(); 103 c.element.removeEventListener("mouseover",c.mouse_over,false); 104 c.element.removeEventListener("mouseout",c.mouse_out,false); 105 c.element.removeEventListener("mousedown",c.mouse_click,false); 106 } 107 108 //mouse event handling class for element, el. 109 function classMausWork(element) 110 { 111 //store information about the element this object is assigned to handle. element, original style, etc. 112 this.element=element; 113 114 var elementStyle=element.getAttribute('style'); 115 var target; 116 117 this.mouse_over=function(ev) 118 { 119 if(gHovering)return; 120 var e=element; 121 var s=e.style; 122 s.backgroundColor='yellow'; 123 s.borderWidth='thin'; 124 s.borderColor='lime'; 125 s.borderStyle='solid'; 126 InfoMSG(ElementInfo(e),'yellow','blue','yellow'); 127 gHoverElement=e; 128 gHovering=true; 129 target=ev.target; 130 ev.stopPropagation(); 131 }; 132 133 this.mouse_out=function(ev) 134 { 135 if(!gHovering)return; 136 if(gHoverElement!=element ||ev.target!=target)return; 137 var e=element; 138 e.setAttribute('style',elementStyle); 139 InfoMSG('-','white','black','white'); 140 gHoverElement=null; 141 gHovering=false; 142 target=null; 143 //ev.stopPropagation(); 144 }; 145 146 this.mouse_click=function(ev) 147 { 148 if(!gHovering)return; 149 if(gHoverElement!=element ||ev.target!=target)return; 150 var e=element; 151 e.setAttribute('style',elementStyle); 152 ev.stopPropagation(); 153 CleanupDOMSelection(); 154 gHoverElement=null; 155 gHovering=false; 156 target=null; 157 158 if(ev.button==0) 159 { 160 gSelectedElement=e; 161 ElementSelected(e); //finished selecting, cleanup then move to next part (section 2), element isolation. 162 } 163 }; 164 165 this.resetElementStyle=function() 166 { 167 element.setAttribute('style',elementStyle); 168 }; 169 } 170 171 function MiscEvent(ev) //keypress, and mouseover/mouseout/mousedown event on body. cancel selecting. 172 { 173 if(ev.type=='mouseout' && !gHovering) 174 { 175 InfoMSG('-','white','black','white'); 176 } 177 else if(ev.type=='mouseover' && !gHovering) 178 { 179 InfoMSG('cancel','yellow','red','yellow'); 180 } 181 else //keypress on document or mousedown on body, cancel ops. 182 { 183 CleanupDOMSelection(); 184 } 185 } 186 187 function InfoMSG(text,color,bgcolor,border) 188 { 189 190 var s=infoDivHover.style; 191 if(color)s.color=color; 192 if(bgcolor)s.backgroundColor=bgcolor; 193 if(border)s.borderColor=border; 194 if(text)hoverText.data=text; 195 } 196 197 198 199 200 201 //(Section 2) Element Isolation 202 function ElementSelected(element) //finished selecting element. setup string to prompt user. 203 { 204 PromptUserXpath(ElementInfo(element)); 205 } 206 207 208 function PromptUserXpath(defaultpath) //prompt user, isolate element. 209 { 210 var userpath = prompt("XPath of elements to isolate : ", defaultpath); 211 if(userpath && userpath.length>0) 212 { 213 var addPredicate = "[count(./ancestor-or-self::head)=0][count(./ancestor-or-self::title)=0]"; //exclude head & title elements from selection so they aren't removed 214 var addPath = "//script | //form | //object | //embed"; //include these elements in selection for removal 215 var pathx=TransformXPath_NoAncestorDescendentSelf(userpath, addPredicate, addPath); //the xpath selection of all elements to be removed/deleted. 216 217 try 218 { 219 var element; 220 var elements=$XPathSelect(pathx); 221 for(var i=0;element=elements(i);i++) 222 { 223 224 if(!element.nodeName.match(/^(head|title)$/i)) //redundant check. 225 { 226 ElementRemove(element); 227 } 228 } 229 } 230 231 catch(err) 232 { 233 alert("wtf: "+err); 234 } 235 236 } 237 } 238 239 240 241 //support 242 function $XPathSelect(p, context) 243 { 244 if (!context) context = document; 245 var i, arr = [], xpr = document.evaluate(p, context, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); 246 return function(x) { return xpr.snapshotItem(x); }; //closure. wooot! returns function-type array of elements (usually elements, or something else depending on the xpath expression). 247 } 248 249 function ElementRemove(e) 250 { 251 if(e)e.parentNode.removeChild(e); 252 } 253 254 function ElementInfo(element) 255 { 256 var txt=''; 257 if(element) 258 { 259 txt=element.tagName.toLowerCase(); //txt=element.tagName; 260 txt=attrib(txt,element,'id'); 261 txt=attrib(txt,element,'class'); 262 txt='//'+txt; 263 } 264 return txt; 265 266 function attrib(t,e,a) 267 { 268 if(e.hasAttribute(a)) 269 { 270 t+="[@"+a+"='"+e.getAttribute(a)+"']"; 271 } 272 return t; 273 } 274 275 } 276 277 278 279 //function to 'invert' the XPath by selecting all elements that are not ancestor and not descendent and not self. 280 function TransformXPath_NoAncestorDescendentSelf(u, includePredicates, includePaths) 281 { 282 283 //sample input (u): //div[@class='sortbox'] 284 //sample output //*[ not(./descendant-or-self::*=//div[@class='sortbox'])][ not(./ancestor-or-self::*=//div[@class='sortbox'])] 285 //sample output with additional conditions: //*[ not(./descendant-or-self::*=//div[@class='sortbox'])][ not(./ancestor-or-self::*=//div[@class='sortbox'])][count(./ancestor-or-self::head)=0][count(./ancestor-or-self::title)=0] 286 287 //obsolete method. much faster but can only be used for limited types of (simple) xpath expressions -- unlike the current version, which should be able to convert any xpath. 288 //input: table[@id='topbar'] 289 //output: //*[not(./descendant-or-self::table[@id='topbar']) and not(./ancestor-or-self::table[@id='topbar'])] 290 //output (alternative): //*[count(./descendant-or-self::table[@id='topbar'])=0 and count(./ancestor-or-self::table[@id='topbar'])=0] 291 292 293 var o1= './descendant-or-self::*='+gr(u); 294 o1= 'not' + gr(o1); 295 o1= nt(o1); 296 var o2= './ancestor-or-self::*='+gr(u); 297 o2= 'not' + gr(o2); 298 o2= nt(o2); 299 300 var o= '//*'+o1+o2; 301 if(includePredicates && includePredicates.length>0) o += includePredicates; 302 if(includePaths && includePaths.length>0) o += ' | ' + includePaths; 303 return o; 304 305 306 function nt(term){return wrap(term,'[]');} //node test; predicate - enclose with bracket. 307 function gr(term){return wrap(term,'()');} //group - parenthesize. 308 function wrap(term, enclosure){return enclosure.charAt(0)+term+enclosure.charAt(1);} 309 } 310 311 312 313 314 })(); 315
Get XPath
Usage:
getXPath(document.getElementById('myelement'));
1 2 function getXPath(node, path) { 3 path = path || []; 4 if(node.parentNode) { 5 path = getXPath(node.parentNode, path); 6 } 7 8 if(node.previousSibling) { 9 var count = 1; 10 var sibling = node.previousSibling 11 do { 12 if(sibling.nodeType == 1 && sibling.nodeName == node.nodeName) {count++;} 13 sibling = sibling.previousSibling; 14 } while(sibling); 15 if(count == 1) {count = null;} 16 } else if(node.nextSibling) { 17 var sibling = node.nextSibling; 18 do { 19 if(sibling.nodeType == 1 && sibling.nodeName == node.nodeName) { 20 var count = 1; 21 sibling = null; 22 } else { 23 var count = null; 24 sibling = sibling.previousSibling; 25 } 26 } while(sibling); 27 } 28 29 if(node.nodeType == 1) { 30 path.push(node.nodeName.toLowerCase() + (node.id ? "[@id='"+node.id+"']" : count > 0 ? "["+count+"]" : '')); 31 } 32 return path; 33 }; 34
Java DOM: Sample XPath Query
1 2 try 3 { 4 XPath xpath = XPathFactory.newInstance().newXPath(); 5 Element e = (Element) xpath.evaluate("/Archive/Section/Description", parentNode, 6 XPathConstants.NODE); 7 printXmlNode(e); 8 } 9 catch (XPathExpressionException e) 10 { 11 e.printStackTrace(); 12 }