orxxe v1.0.2
Openrosa XForms Evaluator
Wrapper for browsers' XPath evaluator with added support for OpenRosa extensions.
For more info on extended XPath expressions/bindings supported by XForms/OpenRosa/OpenDataKit (ODK) see:
Getting Started
Include with
npm install openrosa-xpath-evaluator --saveor manually download and add dist/orxe.min.js file.Include orxe.min.js in the \ of your HTML document. NOTE: Make sure HTML document is in strict mode i.e. it has a !DOCTYPE declaration at the top!
Initialize orxe:
// bind XPath methods to document and window objects // NOTE: This will overwrite native XPath implementation if it exists orxe.bindDomLevel3XPath();You can now use XPath expressions to query the DOM:
var result = document.evaluate( '//ul/li/text()', // XPath expression document, // context node null, // namespace resolver XPathResult.ORDERED_NODE_SNAPSHOT_TYPE ); // loop through results for (var i = 0; i < result.snapshotLength; i++) { var node = result.snapshotItem(i); alert(node.nodeValue); }
External Libraries
This library does not depend on any external libraries. But the odk digest function can be supported by installing the node-forge library.
Supported XPath expressions:
/model/instance[1]//*/model/instance[1]/*/meta/*./authorauthorfirst.name/bookstore//authorauthor/first-namebookstore//titlebookstore/*/titlebookstore//book/excerpt//emph.//titleauthor/*book/*/last-name@styleprice/@exchangeprice/@exchange/totalbook[@style]book/@style./first-namefirst-nameauthor[1]author[first-name][3]my:bookx/y[1]x[1]/y[2]book[excerpt]book[excerpt]/titlebook[excerpt]/author[degree]book[author/degree]author[degree][award]ancestor::book[1]ancestor::book[author][1]ancestor::author[parent::book][1]*/**[@specialty]@*@my:*my:*author[degree and award]author[(degree or award) and publication]author[degree and not(publication)]author[not(degree or award) and publication]author[. = "Matthew Bob"]author[last-name = "Bob" and ../price > 50]author[not(last-name = "Bob")]author[first-name = "Bob"]author[last-name = "Bob" and first-name = "Joe"]author[* = "Bob"]author[last-name = "Bob"]author[last-name[1] = "Bob"]author[last-name [position()=1]= "Bob"]book[last()]book/author[last()]book[position() <= 3]book[/bookstore/@specialty=@style]degree[position() < 3]degree[@from != "Harvard"]p/text()[2]price[@intl = "Canada"]x/y[position() = 1](book/author)[last()](x/y)[1]- `today() < (today() + 1)
- `today() < '1970-06-03'
- `today() + 1 < '1970-06-03'
- `today() + 1 > '1970-06-03'
../some-path='some-value''some-value'=../some-path/simple/xpath/to/node < today() + 1"aardvark" < "aligator"self::node()namespace::node()child::node()descendant::node()descendant-or-self::node()parent::node()following-sibling::node()preceding-sibling::node()namespace::node()preceding-sibling::node()following::node()preceding::node()attribute::node()boolean('a')boolean('')boolean(true())boolean(false())boolean(1)boolean(-1)boolean(1 div 0)boolean(0.1)boolean('0.0001')boolean(0)boolean(0.0)boolean(number(''))boolean(/xhtml:html)boolean(/asdf)boolean(//xhtml:article)boolean(self::node())ceiling(-1.55)ceiling(2.44)ceiling(0.001)ceiling(1.5)id('ComparisonOperatorCaseNodesetNegative5to5')/* < *lang('en')lang('EN-us')attribute::*namespace::*child::*ancestor-or-self::*namespace::ns2:*namespace::ns2:ns2attribute::attrib3child::node()child::text()child::comment()child::processing-instruction()child::processing-instruction('custom-process-instruct')id('FunctionNodesetIdCaseSimple')last()xhtml:p[last()]last(1)*[position()=last()]count(xhtml:p)local-name(namespace::node())local-name(1, 2)local-name(1)namespace-uri(1, 2)namespace-uri(1)number(-1.0)number(1)number(0.199999)sum(1, 2)ceiling(-1.55)round(-1.55)sum(self::*)sum(*)sum(node())string('As Df')string(attribute::node()[1])string(namespace-uri(/*))string(namespace::node())starts-with('a', '')contains('asdf', 'sd')substring-before('ab', 'a')substring-after('aab', 'a')substring('12345', 2)string-length('a')normalize-space(' a')translate('aabb', 'ab', 'ba')id('eee40') | id('eee20') | id('eee25') | id('eee10') | id('eee30') | id('eee50')id('eee40')/attribute::*[1] | id('eee30')id('nss25')/namespace::*id('nss40')/namespace::* | id('nss40')/namespace::*abs(10.5)area("7.9377 -11.5845 0 0;7.9324 -11.5902 0 0;7.927 -11.5857 0 0;7.925 -11.578 0 0;7.9267 -11.5722 0 0;7.9325 -11.5708 0 0;7.9372 -11.5737 0 0;7.9393 -11.579 0 0;7.9377 -11.5845 0 0")distance("7.9377 -11.5845 0 0;7.9324 -11.5902 0 0;7.927 -11.5857 0 0;7.925 -11.578 0 0;7.9267 -11.5722 0 0;7.9325 -11.5708 0 0;7.9372 -11.5737 0 0;7.9393 -11.579 0 0;7.9377 -11.5845 0 0")boolean-from-string('whatever')checklist(-1, 2, 2>1)coalesce(/simple/xpath/to/node, "whatever")coalesce("FIRST", "whatever")count-non-empty(//xhtml:div[@id="FunctionCountNonEmpty"]/xhtml:div)count-selected(self::node())date-time('1970-01-01')number(date('1970-01-01'))date('2100-01-02') > now()today() > ('2012-01-01' + 10)decimal-date-time("1969-12-31T00:00:00Z")decimal-date("1969-12-31")decimal-time("06:60:00.000-07:00")digest("abc", "MD5", "hex")ends-with("ba", "a")false("a")floor(-1.005)format-date-time("2001-12-31", "%b %e, %Y")if(true(), 5, "abc")if(self::node(), "exists", "does not exist")int(/simple/xpath/to/node)int(7.922021953507237e-12)join(" :: ", //item)join(" ", "This", "is", "a", "sentence.")max(/simple/xpath/to/node)max(self::*)max(*)min(/simple/xpath/to/node)not(true())not(false())once("aa")once(. * 10)position(..)position(.)position(../..)pow(/simple/xpath/to/node, 0)pow(2.5, 2)random()randomize(//xhtml:div[@id="FunctionRandomize"]/xhtml:div, 'a')regex(/simple/xpath/to/node, "[0-9]{3}")round("-50.55", "-2")selected-at('zero one two three', '4')selected("apple baby crimson", " baby ")substr(/simple/xpath/to/node, 5)sum(*)sum(self::*)sum(node())sum(*)sum(/root/item)sin(2)cos(2)tan(2)acos(0.5)asin(0.5)atan(0.5)log(2)log10("a")pi()exp(2)exp10(2)sqrt(4)uuid()uuid(6)weighted-checklist(-1, 2, 2>1, 2)
Unsupported XPath expressions:
(Add any examples of known-unsupported expressions here and to test/extended-xpath.spec.js.)
Support for custom functions:
To support custom functions, this library can be extended with the following.
orxe.customXPathFunction.add('comment-status', function(a) {
if(arguments.length !== 1) throw new Error('Invalid args');
const curValue = a.v[0]; // {t: 'arr', v: [{'status': 'good'}]}
const status = JSON.parse(curValue).status;
return new orxe.customXPathFunction.type.StringType(status);
});The arguments passed to the custom function (string, number, xpath) will determine the arguments passed by the library to the function implementation. The argument format will be any of these:
{t: 'arr', v:[]}
{t: 'num', v:123}
{t: 'str', v:'123'}The return types currently supported are these:
orxe.customXPathFunction.type.StringType
orxe.customXPathFunction.type.NumberType
orxe.customXPathFunction.type.BooleanType
orxe.customXPathFunction.type.DateTypeConfiguration support
The library can be configured with:
orxe.config = {
allowStringComparison: false,
includeTimeForTodayString: false,
returnCurrentTimeForToday: false
};allowStringComparison (default: false)
This flag allows comparing expressions like this: 'bcd' > 'abc'.
includeTimeForTodayString (default: false)
This flag allows the inclusion of time for today() expressions that expect XPathResult.STRING_TYPE.
returnCurrentTimeForToday (default: false)
This flag allows time to be considered for today() expressions that expect XPathResult.ANY_TYPE, XPathResult.NUMBER_TYPE, etc.
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago