<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -322,3 +322,67 @@ DomPredictionHelper.prototype.invertObject = function(object) {
   });
   return new_object;
 };
+
+DomPredictionHelper.prototype.cssToXPath = function(css_string) {
+  var tokens = this.tokenizeCss(css_string);
+  if (tokens[0] &amp;&amp; tokens[0] == ' ') tokens.splice(0, 1);
+  if (tokens[tokens.length - 1] &amp;&amp; tokens[tokens.length - 1] == ' ') tokens.splice(tokens.length - 1, 1);
+
+  var css_block = [];
+  var out = &quot;&quot;;
+  
+  for(var i = 0; i &lt; tokens.length; i++) {
+    if (tokens[i] == ' ') {
+      out += this.cssToXPathBlockHelper(css_block);
+      css_block = [];
+    } else {
+      css_block.push(tokens[i]);
+    }
+  }
+  
+  return out + this.cssToXPathBlockHelper(css_block);
+};
+
+// Process a block (html entity, class(es), id, :nth-child()) of css
+DomPredictionHelper.prototype.cssToXPathBlockHelper = function(css_block) {
+  if (css_block.length == 0) return '//';
+  var out = '//';
+  var first = css_block[0].substring(0,1);
+  
+  if (first == ',') return &quot; | &quot;;
+
+  if (jQuery.inArray(first, [':', '#', '.']) != -1) {
+    out += '*';
+  }
+  
+  var expressions = [];
+  var re = null;
+
+  for(var i = 0; i &lt; css_block.length; i++) {
+    var current = css_block[i];
+    first = current.substring(0,1);
+    var rest = current.substring(1);
+    
+    if (first == ':') {
+      // We only support :nth-child(n) at the moment.
+      if (re = rest.match(/^nth-child\((\d+)\)$/))
+        expressions.push('(((count(preceding-sibling::*) + 1) = ' + re[1] + ') and parent::*)');
+    } else if (first == '.') {
+      expressions.push('contains(concat( &quot; &quot;, @class, &quot; &quot; ), concat( &quot; &quot;, &quot;' + rest + '&quot;, &quot; &quot; ))');
+    } else if (first == '#') {
+      expressions.push('(@id = &quot;' + rest + '&quot;)');
+    } else if (first == ',') {
+    } else {
+      out += current;
+    }
+  }
+  
+  if (expressions.length &gt; 0) out += '[';
+  for (var i = 0; i &lt; expressions.length; i++) {
+    out += expressions[i];
+    if (i &lt; expressions.length - 1) out += ' and ';
+  }
+  if (expressions.length &gt; 0) out += ']';
+  return out;
+};
+</diff>
      <filename>lib/dom.js</filename>
    </modified>
    <modified>
      <diff>@@ -310,6 +310,14 @@ SelectorGadget.prototype.refreshFromPath = function(e) {
   self.setPath(path);
 };
 
+SelectorGadget.prototype.showXPath = function(e) {
+  var self = (e &amp;&amp; e.data &amp;&amp; e.data.self) || this;
+  var path = self.path_output_field.value;
+  if (path == 'No valid path found.') return;
+  prompt(&quot;The CSS selector '&quot; + path + &quot;' as an XPath is shown below.  Please report any bugs that you find with this converter.&quot;, 
+         self.prediction_helper.cssToXPath(path));
+};
+
 SelectorGadget.prototype.clearSelected = function(e) {
   var self = (e &amp;&amp; e.data &amp;&amp; e.data.self) || this;
   self.selected = [];
@@ -358,9 +366,16 @@ SelectorGadget.prototype.makeInterface = function() {
     }
   }).addClass('sg_ignore'));
 
+  this.sg_div.append(jQuery('&lt;input type=&quot;button&quot; value=&quot;XPath&quot;/&gt;').bind(&quot;click&quot;, {'self': this}, this.showXPath).addClass('sg_ignore'));
+
   this.sg_div.append(jQuery('&lt;input type=&quot;button&quot; value=&quot;Help&quot;/&gt;').bind(&quot;click&quot;, {'self': this}, this.showHelp).addClass('sg_ignore'));
 
   this.sg_div.append(jQuery('&lt;input type=&quot;button&quot; value=&quot;X&quot;/&gt;').bind(&quot;click&quot;, {'self': this}, this.unbind).addClass('sg_ignore'));
+
+  // this.sg_div.append( 
+  //   jQuery('&lt;span class=&quot;sg_ignore sg_option sg_new_line&quot;&gt;Show XPath&lt;/span&gt;').bind(&quot;click&quot;, {'self': this}, this.showXPath)
+  // );
+
   jQuery('body').append(this.sg_div);
 
   this.path_output_field = path.get(0);
@@ -380,6 +395,12 @@ SelectorGadget.prototype.unbind = function(e) {
   self.clearSelected();
 };
 
+SelectorGadget.prototype.setOutputMode = function(e, output_mode) {
+  var self = (e &amp;&amp; e.data &amp;&amp; e.data.self) || this;
+  self.output_mode = (e &amp;&amp; e.data &amp;&amp; e.data.mode) || output_mode;
+  
+};
+
 SelectorGadget.prototype.rebind = function() {
   this.unbound = false;
   this.makeInterface();</diff>
      <filename>lib/interface.js</filename>
    </modified>
    <modified>
      <diff>@@ -204,4 +204,13 @@ img.sg_selected{
 }
 #_sg_path_field{
   width:400px !important;
+}
+#_sg_div .sg_new_line {
+  clear: both;
+}
+#_sg_div .sg_option {
+  float: left;
+}
+#_sg_div .sg_selected_option {
+  text-decoration: underline;
 }
\ No newline at end of file</diff>
      <filename>lib/selectorgadget.css</filename>
    </modified>
    <modified>
      <diff>@@ -199,6 +199,45 @@
     assertFalse(dom.wouldLeaveFreeFloatingNthChild([&quot;a&quot;], 0));
     assertFalse(dom.wouldLeaveFreeFloatingNthChild([&quot;:nth-child(0)&quot;], 0));
   }
+  
+  function testCssToXPath() {
+    var dom = new DomPredictionHelper();
+    
+    var expressions = ['a', '#leaf1', 'body #leaf1', 'span.sibling.something.else', 'a , b , #leaf1', 
+                       'span.sibling', '.else.something', ':nth-child(2) i#leaf1', 'span.something.else:nth-child(2) i#leaf1'];
+    
+    for (var i = 0; i &lt; expressions.length; i++) {
+      var css = expressions[i];
+      var xpath = dom.cssToXPath(css);
+      if (!cssAndXPathMatch(css, dom.cssToXPath(css))) {
+        console.log(css + ' LIKE ' + xpath);
+      }
+    }
+  }
+  
+  function cssAndXPathMatch(css, xpath) {
+    var css_matches = jQuery(css);
+    var elements = [];
+    for (var i = 0; i &lt; css_matches.length; i++) {
+      elements.push(css_matches.get(i));
+    }
+    
+    var elems = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null);
+    var elem = elems.iterateNext();
+    var pos = -1;
+    while (elem){
+      pos = jQuery.inArray(elem, elements);
+      if (pos == -1) {
+        return false;
+      } else {
+        elements.splice(pos, 1);
+      }
+      var elem = elems.iterateNext();
+    }
+    if (elements.length == 0) return true;
+    return false;
+  }
+  
 &lt;/script&gt;
   &lt;/head&gt;
 </diff>
      <filename>test/testDom.html</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>04e5d15f0172d6e700c3c00865c8a95475ff08b8</id>
    </parent>
  </parents>
  <author>
    <name>Andrew Cantino</name>
    <email>cantino@gmail.com</email>
  </author>
  <url>http://github.com/iterationlabs/selectorgadget/commit/a306453d1e8f54daeee11e4b7f70b83836a8a17f</url>
  <id>a306453d1e8f54daeee11e4b7f70b83836a8a17f</id>
  <committed-date>2009-03-10T15:53:32-07:00</committed-date>
  <authored-date>2009-03-10T15:53:32-07:00</authored-date>
  <message>xpath generation</message>
  <tree>7c1a1ed97adfbb982bb79591d7a233791ce6a58e</tree>
  <committer>
    <name>Andrew Cantino</name>
    <email>cantino@gmail.com</email>
  </committer>
</commit>
