【Apple Script】Javascript の 要素検索に XPathを使う

Apple Script の中で、

Javascript の 要素検索に XPathを使う関数を作成。

返り値は フルXPathで、複数ならカンマ区切りの文字列。


on getXPathsByXPath(args)

    set {debug_:aDebug, text_:aText, xpath_:aXPath, isScroll_:aIsScroll} to ¬
        args & {debug_:false, text_:"", xpath_:"", isScroll_:false}

    tell application "Safari"

        set cnt_max to 20
        set cnt_current to 0

        if aIsScroll then
            do JavaScript "window.scroll(0, 0);" in document 1
        end if

        repeat cnt_max times

            set cnt_current to cnt_current + 1

            if aIsScroll then

                do JavaScript "

            var element = document.documentElement;
            var bottom = element.scrollHeight - element.clientHeight;
            var scrollY = 0;

            scrollY = (bottom / " & cnt_max & ") * " & cnt_current & ";

            window.scroll(0, scrollY);
            " in document 1

            end if

            if aIsScroll then
                delay 0.1
            end if

            set val to do JavaScript "

" & my getJsFuncXPath2() & "
" & my getJsFuncXPath() & "

        res_list = new Array();

        var lists = document.getElementsByXPath('" & aXPath & "');

        for ( var i = 0; i < lists.length; i++ ) {
            var ele = lists[i];
            var xpath = getXpath(ele);
            res_list.push(xpath);
        }

        if (res_list.length > 0) {
            res = res_list.join(',');
        }else{
            res = '';
        }

        " in document 1

            if val is not "" then
                return val
            end if

            delay 0.1
        end repeat
        return ""
    end tell
end getXPathsByXPath

on getJsFuncXPath()

    return "

function getXpath(element) {
  if(element && element.parentNode) {
    var xpath = getXpath(element.parentNode) + '/' + element.tagName;
    var s = [];

    for(var i = 0; i < element.parentNode.childNodes.length; i++) {
      var e = element.parentNode.childNodes[i];
      if(e.tagName == element.tagName) {
        s.push(e);
      }
    }

    if(1 < s.length) {
      for(var i = 0; i < s.length; i++) {
        if(s[i] === element) {
          xpath += '[' + (i+1) + ']';
          break;
        }
      }
    }

    return xpath.toLowerCase();
  } else {
    return '';
  }
}
    "

end getJsFuncXPath

on getJsFuncXPath2()

    return "
document.getElementsByXPath = function(expression, parentElement) {
    var r = []
    var x = document.evaluate(expression, parentElement || document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)
    for (var i = 0, l = x.snapshotLength; i < l; i++) {
        r.push(x.snapshotItem(i))
    }
    return r
}
    "
end getJsFuncXPath2

参考サイト