views:

1453

answers:

3

Given:

<tr>
  <td><a href="http://foo.com"&gt;Keyword 1</a></td>
  <td><a href="http://bar.com"&gt;Keyword 2</a></td>
  <td><a href="http://wombat.com"&gt;Keyword 3</a></td>
</tr>

<tr>
  <td><a href="http://blah.com"&gt;Keyword 4</a></td>
  <td><a href="http://woof.com"&gt;Keyword 5</a></td>
  <td><a href="http://miaow.com"&gt;Keyword 6</a></td>
</tr>

I need to match each URI within the table cells. The keyword is consistent throughout the document. I can match links for the entire document with no trouble:

var links_in_document = document.evaluate(
  "//a[starts-with(text(),'Keyword')]",
  document,
  null,
  XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
  null);

However, even though I have an easy way to reference the TR node, I can't seem to find the right XPath to obtain the links in the row. The snippet below seems to give me the first link in the first TD, but not the rest. Help?

var links_in_row = document.evaluate(
  ".//a[starts-with(text(),'Keyword')]",
  row,
  null,
  XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
  null);

(where 'row' is the context node).

Edited: perhaps I wasn't clear, I can find the links from document level just fine. I am trying to isolate the links in a single row by using the TR node as the context for the XPath.

Edit: solution, for interest. The broken markup I was working on had no id attributes, so I added some and was able to proceed. Snippet:

var exhibit_link;
for( var i = 0; i < all_exhibit_links.snapshotLength; i++ ) {
  exhibit_link = all_exhibit_links.snapshotItem( i );

  // The rows have no unique ID, so we need to give them one.
  // This will give the XPath something to 'latch onto'.
  exhibit_link.parentNode.parentNode.id = 'ex_link_row_' + i.toString();

  exhibit_link.addEventListener( "click", 
    function( event ) {
      var row_id = event.target.parentNode.parentNode.id;

      // Find only those links that are within rows with the corresponding id
      var row_links = document.evaluate(
        "id('" + row_id + "')/td/a[starts-with(text(),'Exhibit')]",
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null);

      // Open each link in a new tab
      for( var j = 0; j < row_links.snapshotLength; j++ ) {
        row_link = row_links.snapshotItem( j );
        GM_openInTab( row_link.href );
      }

      // Suppress the original function of the link
      event.stopPropagation();
      event.preventDefault();
    }, 
    true );
}
+3  A: 

a quick test in the JavaScript Shell with your html example and the following code:

var links_in_row = document.evaluate( ".//a[starts-with(text(),'Keyword')]"
          , document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
var i = 0;
while( (link = links_in_row.snapshotItem(i) ) != null) {
   print(link.innerHTML);i++;
}

prints out:

Keyword 1
Keyword 2
Keyword 3

which suggests it is working correctly. Only change i made was not to start at the row level, but at the document...

bert
I got the same result with the same code, more or less. Must be something outside what was copy-pasted here.
anschauung
Edited to clarify: I can find them within the document context, but isolating a single row is proving difficult.
EloquentGeek
A: 

Try:

descendant::*[self::a[starts-with(text(), 'Keyword')]]
ScottSEA
A: 

Extending on what bert wrote, this works for me.

var rows = document.evaluate( "//tr"
          , document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
var i = 0;
while( (row = rows.snapshotItem(i) ) != null) {
    print( 'NEW ROW----');
    var links = document.evaluate(".//a[starts-with(text(),'Keyword')]",
                                  row, null, 
                                  XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
    var k = 0;
    while ((link = links.snapshotItem(k)) != null) {
       print( link.innerHTML );
       k++;
    }
    i++;
}

Prints out:

NEW ROW----
Keyword 1
Keyword 2
Keyword 3
NEW ROW----
Keyword 4
Keyword 5
Keyword 6

I think there's something missing outside of what was copy pasted.

bert should get the answer for this one IMHO.

seth