This chapter describes the Object API built into Server-Side JavaScript in MarkLogic and includes the following sections:
MarkLogic APIs often return or expect nodes and/or documents. To make it easy to use these APIs in JavaScript, MarkLogic has added the built-in Node
and Document
objects. These are objects but they are not part of the global object. This section describes the interface for these objects and includes the following parts:
A Node
can be any kind of node, such as an element node, a document node, a text node, and so on. If a function returns a Node in Server-Side JavaScript, you can examine the Node
object using the following properties:
For additional DOM properties available on XML nodes (document, element, attribute, processing instruction, and comment), see Node Object for XML Nodes.
The following is an example of using the xpath
function on a Node object. The cts.doc function returns a Node, specifically a Document node, which inherits an xpath
method from Node. The second parameter to Node.xpath binds the XML namespace prefix bar to the XML namespace URI bar.
// assume a document created as follows: declareUpdate(); xdmp.documentInsert("/my/doc.xml", fn.head(xdmp.unquote( '<bar:foo xmlns:bar="bar"><bar:hello><bar:goodbye \n\ attr="attr value">bye</bar:goodbye>\n\ </bar:hello>\n\ </bar:foo>'))); // Use the Node.xpath method on the document node: const node = cts.doc("/my/doc.xml"); node.xpath("//bar:goodbye/@attr", {"bar":"bar"}); // Running in Query Console displays the following value (as an // attribute node): "attr value"
The Document
object inherits all of the properties from the Node Object above, and has the following additional properties:
MarkLogic implements XML DOM APIs to provide read-only access to XML nodes. This section describes these APIs and includes the following parts:
In addition to the Node
properties described in Node Object, the XML node types all have a subset of the W3C DOM API of Node
, as follows:
The DOM APIs provide read-only access to the XML nodes; any DOM APIs that attempt to modify the nodes will raise the DOM error NO_MODIFICATION_ALLOWED_ERR
.
The Document
object inherits all of the properties from the Node Object for XML Nodes above (in addition to the properties from the Node Object), and has the following additional properties:
The NodeBuilder API makes it easy to construct nodes in JavaScript, including XML nodes and JSON nodes, and has the following functions and properties:
In order to use anything created with NodeBuilder as a node, you must first call toNode()
.
The following is an example of creating an XML document node:
const x = new NodeBuilder(); x.startDocument(); x.startElement("foo", "bar"); x.addText("text in bar"); x.endElement(); x.endDocument(); const newNode = x.toNode(); newNode; // returns a document node with the following serialization: // <?xml version="1.0" encoding="UTF-8"?> // <foo xmlns="bar">text in bar</foo>
The following properties and functions are available on element nodes:
The following properties are available on attribute (Attr
) nodes, in addition to the XMLNode properties which it inherits:
The CharacterData inherits all of the APIs from an XMLNode plus the following additional properties and methods. It has subtypes that inherit from Text node, Comment nodes, and Processing Instruction nodes, which are also included in the table.
The following are the functions and properties of TypeInfo. Additionally, it has the schema component methods bound to it.
The following are the functions and properties of NamedNodeMap.
The NodeList
is an iterator that has the following additional properties.
Properties | Description |
---|---|
length |
Number of nodes in the list. |
item(Number index) |
Get the item at the index place (first, second, and so on). |
Value
is an object class that wraps MarkLogic XQuery types, enabling you to pass these objects into functions that are designed for those types.
Value
supports valueOf
and toObject
methods for converting the underlying value to its closest native JavaScript value or object. For more details, see Value in the MarkLogic Server-Side JavaScript Function Reference.
Any builtin function whose signature indicates an XML atomic return type such as xs.date
, xs.int
, or xs.string
returns a Value
object. A function whose signature indicates a native JavaScript type such as number, boolean, or string returns a simple, native value.
For example, the fn.currentDate builtin function returns a Value
representing an xs:date
, and its return type in the MarkLogic Server-Side JavaScript Function Reference is xs.date
. It returns a Value object that contains an XQuery xs:date
value. This enables you to pass the result to date-specific functions such as xdmp.weekFromDate.
Similarly, lexicon functions such as cts.values, cts.words, and cts.geospatialBoxes return a Sequence
of Value
objects rather than native JavaScript objects in order to preserve type and support passing the Sequence
items to cts.frequency.
See the following topics for more details:
JavaScript has no native equivalent to xs:date
. Such values can only be represented natively as a string, which loses the dateness of the value. The string has to be parsed back into a date before you can use it as input to a function that expects an xs:date
:
xdmp.daynameFromDate(xs.date('1997-07-20'));
A DateTime function such as fn.currentDate returns a Value
object representing an XQuery xs:date
value. The following test returns true:
fn.currentDate() instanceof Value
The Value
returned by fn.currentDate can be passed directly into functions that expect an xs.date
, such as xdmp.daynameFromDate without conversion from a string:
xdmp.daynameFromDate(fn.currentDate());
If you probe the value returned by fn.currentDate, you can see it is not a native JavaScript type:
typeof fn.currentDate(); // object Object.prototype.toString.call(fn.currentDate()); // [object xs.date]
For more details about dates, see Dates in Server-Side JavaScript.
You can use a Value
like a native JavaScript value in contexts in which loose equality is sufficient. For example, when comparing a Value
to a number using the == operator:
someDecimalValue == 1
You cannot successfully compare a Value
to a native JavaScript value in contexts where strict equality or same value equality is used, such as the === operator, Array.prototype.indexOf
, or Array.prototype.includes
.
For more details, see Example: Comparison between a Value and a Number.
Suppose you call cts.values on a lexicon over xs:int
values. The return value will be a Sequence containing Value objects that represent integer values. Supposed the first item in the returned Sequence
contains a Value
object equivalent to the number 10. Then following expressions evaluate to the results shown:
const mlValues = cts.values(cts.pathReference('/my/int/property')); fn.head(mlValues) == 10; // true fn.head(mlValues) === 10; // false fn.head(mlValues).valueOf() === 10; // true mlValues.toArray().includes(10); // false mlValues.toArray().indexOf(10); // -1 (no match) fn.head(mlValues) instanceof Value; // true typeof fn.head(mlValues); // 'object' typeof fn.head(mlValues).valueOf(); // 'number'
When you store JSON in a MarkLogic database, it is stored as a document node with a JSON node child. You can access JSON documents stored in the database with fn.doc, or with any other function that returns a document. You have direct read-only access to the JSON nodes through the native JavaScript properties, including get a named property, querying for the existence of a named property, and enumerate all available named properties.
If you want to convert a JavaScript object to a JSON node, you can call xdmp.toJson
on the JavaScript object and it will return a JSON node.
For more details about JSON nodes and documents, see Working With JSON in the Application Developer's Guide.
A Sequence
is a JavaScript Iterable
object that represents a set of values. Many MarkLogic functions that return multiple values do so in Server-Side JavaScript by returning a Sequence
. An iterable is a JavaScript object which returns an iterator object from the @@iterator
method.
You can iterate over the values in a Sequence
using a for..of loop
. For example:
for (const doc of fn.collection('/my/coll')) { // do something with doc }
If you want to extract just the first (or only) item in a Sequence
without iteration, use fn.head. For example, the xdmp.unquote function returns a Sequence
, but in many cases it is a Sequence
containing only one item, so you could extract that single result with code like the following:
const node = fn.head(xdmp.unquote('<data>some xml</data>'))
You can create your own Sequence
object from an array, an array-like, or another iterable using Sequence.from. For example, the following code snippet creates a Sequence
from an array:
const mySeq = Sequence.from([1,2,3,4]);
Use fn.count to count the number of items in a Sequence
. For example:
const mySeq = Sequence.from([1,2,3,4]); fn.count(mySeq); // returns 4
For more details, see Sequence Object in the MarkLogic Server-Side JavaScript Function Reference.
This interface is deprecated. As of MarkLogic 9, no MarkLogic functions return a ValueIterator
or accept a ValueIterator
as input. Use the guidelines in this section to transition your code to Sequence.
Code that manipulates ValueIterator
results as described in the following table will continue to work transparently when the return type is Sequence
.
Code that depends on the ValueIterator
properties and methods next
, count
, and clone
cannot used with a Sequence
value.
You can use the instanceof
operator to create code that behaves differently, depending on whether you are working with a ValueIterator
or a Sequence
. No MarkLogic 8 functions will return a Sequence
, so you can be certain that code will not execute in MarkLogic 8.
For example, the following code uses ValueIterator.clone to preserve a set of values across iteration in MarkLogic 8, but skips the unnecessary cloning when the result type becomes Sequence.
const results = cts.uris('/', ['limit=10']); const clone = {}; if (uris instanceof ValueIterator) { // iterator destructive, so clone to preserve orig clone = results.clone(); } else if (results instanceof Sequence) { // iteration is not destructive, no clone needed clone = results; } for (const val of clone) { // do something with val }
The JavaScript instanceof
operator is available to test MarkLogic types (in addition to JavaScript types). For example, the following returns true:
const a = Sequence.from(["saab", "alfa romeo", "tesla"]); a instanceof Sequence; // returns true
Similarly, the following are some other examples of using instaceof
with MarkLogic and JavaScript object types.
const a = fn.currentDate(); a instanceof xs.date; // returns true
const a = fn.currentDate().toObject(); a instanceof xs.date; // returns false
A JavaScript Date
object type:
const a = fn.currentDate().toObject(); a instanceof Date; // returns true
You can test for any of the following MarkLogic object types using instanceof
:
Value
(all MarkLogic Object types are subtypes of Value
)xs.anyAtomicType
cts.query (
and all of its subtypes--the subtypes are also instance of cts.query)
ArrayNode
BinaryNode
BooleanNode
ObjectNode
XMLNode
Document
Node
NodeBuilder
Attr
CharacterData
Comment
Text
Element
ProcessingInstruction
XMLDocument
ValueIterator
The following is an example using an XML document:
// assume "/one.xml" has content <name>value</name> const a = fn.head(fn.doc("/one.xml")).root; const b = fn.head(a.xpath("./text()")); b instanceof Text; // returns true
The following is an example using a JSON document:
// Assume "/car.json" has the content: // {"car":"The fast electric car drove down the highway."} const res = new Array(); const a = fn.head(fn.doc("/car.json")); res.push(a instanceof Document); const b = a.root; res.push(b instanceof ObjectNode); res; // returns [true, true]
Similarly, you can test for any XML type. Note that the XML types in JavaScript have a dot (.
) instead of a colon (:
) between the namespace and the type name. For example, xs.integer
, xs.string
, and so on.
When errors and exceptions are thrown in a Server-Side JavaScript program, a stack is thrown and can be caught using a standard JavaScript try/catch
block. For details about each individual error message, see the Messages and Codes Reference Guide. This section includes the following parts:
The following is the API available to JavaScript exceptions.
Properties/Functions | Description |
---|---|
code |
A string representing the code number.Only available for DOM errors, where the number is the DOM error code. |
data |
An array of strings containing the data thrown with the error. |
message |
The Error message string. |
name |
The error code string. |
retryable |
A boolean indicating if the error is retryable. |
stack |
The JavaScript stack. If the error is thrown from XQuery, the stack contains the concatenated stack from both XQuery and JavaScript. |
stackFrame |
An array of stack frames. See the stackFrame table below for details. For details, see JavaScript stackFrame Properties. |
toString() |
A formatted error message populated with data. |
The following is the API available to each stackFrame
:
The following is a simple JavaScript try/catch
example:
try{ xdmp.documentInsert("/foo.json", {"foo": "bar"} ); } catch (err) { err.toString(); } => catches the following error ( because it is missing the declareUpdate() call ) XDMP-UPDATEFUNCTIONFROMQUERY: xdmp:eval("// query try{ xdmp.documentInsert("/foo.json", {&q...", ()) -- Cannot apply an update function from a query
MarkLogic implements a console
object, which contains functions to do things that log output to ErrorLog.txt in the MarkLogic data directory. The following are the console
functions:
XQuery has operators that allow you to perforn date math on duration typed data to do things like subtract durations to return dateTime values. In Server-Side JavaScript, you can get data returned in the various dateTime duration types and use the duration methods to add, subtract, multiply, divide and compare those durations. This section describes these duration arithmetic and comparison methods and includes the following parts:
Arithmetic methods are available on the following duration objects:
The JavaScript object that is an instance of xs.yearMonthDuration
is analogous to and has the same lexical representation to the XQuery xs:yearMonthDuration
type, as described http://www.w3.org/TR/xpath-functions/#dt-yearMonthDuration. The following methods are available on xs.yearMonthDuration
objects:
The following are some simple examples using these methods:
const v1 = xs.yearMonthDuration("P3Y7M"); const v2 = xs.yearMonthDuration("P1Y4M"); const r = { "v1 + v2" : v1.add(v2), "v1 - v2" : v1.subtract(v2), "v1 * 2" : v1.multiply(2), "v1 / 2" : v1.divide(2), "v1 / v2" : v1.divide(v2) }; r; /* returns: {"v1 + v2":"P4Y11M", "v1 - v2":"P2Y3M", "v1 * 2":"P7Y2M", "v1 / 2":"P1Y10M", "v1 / v2":2.6875} */
The JavaScript object that is an instance of xs.dayTimeDuration
is analogous to and has the same lexical representation to the XQuery xs:dayTimeDuration
type, as described http://www.w3.org/TR/xpath-functions/#dt-dayTimeDuration. The following methods are available on xs.dayTimeDuration
objects:
The following are some simple examples using these methods:
const v1 = xs.dayTimeDuration("P5DT4H"); const v2 = xs.dayTimeDuration("P1DT1H"); const r = { "v1 + v2" : v1.add(v2), "v1 - v2" : v1.subtract(v2), "v1 * 2" : v1.multiply(2), "v1 / 2" : v1.divide(2), "v1 / v2" : v1.divide(v2) }; r; /* returns: {"v1 + v2":"P6DT5H", "v1 - v2":"P4DT3H", "v1 * 2":"P10DT8H", "v1 / 2":"P2DT14H", "v1 / v2":4.96} */
Methods are available on the following duration, date, and dateTime objects:
The following methods are available on xs.dateTime
objects:
The following are some simple examples using these methods:
const v1 = xs.dateTime(xs.date('2013-08-15'), xs.time('12:30:45-05:00')) const v2 = xs.dateTime(xs.date('2012-04-01'), xs.time('01:10:25-02:00')) const v3 = xs.yearMonthDuration("P3Y3M") const v4 = xs.dayTimeDuration("PT1H") const r = { "v1 + v3" : v1.add(v3), "v1 + v4" : v1.add(v4), "v1 - v2" : v1.subtract(v2), "v1 - v3" : v1.subtract(v3), "v1 - v4" : v1.subtract(v4) }; r; /* returns: {"v1 + v3":"2016-11-15T12:30:45-05:00", "v1 + v4":"2013-08-15T13:30:45-05:00", "v1 - v2":"P501DT14H20M20S", "v1 - v3":"2010-05-15T12:30:45-05:00", "v1 - v4":"2013-08-15T11:30:45-05:00"} */
The following methods are available on xs.date
objects:
The following are some simple examples using these methods:
const v1 = xs.date('2013-08-15') const v2 = xs.date('2012-04-01') const v3 = xs.yearMonthDuration("P3Y3M") const v4 = xs.dayTimeDuration("P1DT3H") const r = { "v1 + v3" : v1.add(v3), "v1 + v4" : v1.add(v4), "v1 - v2" : v1.subtract(v2), "v1 - v3" : v1.subtract(v3), "v1 - v4" : v1.subtract(v4) }; r; /* returns: {"v1 + v3":"2016-11-15", "v1 + v4":"2013-08-16", "v1 - v2":"P501D", "v1 - v3":"2010-05-15", "v1 - v4":"2013-08-13"} */
The following methods are available on xs.time
objects:
The following are some simple examples using these methods:
const v1 = xs.time('12:30:45-05:00') const v2 = xs.time('01:10:25-02:00') const v3 = xs.dayTimeDuration("PT1H") const r = { "v1 + v3" : v1.add(v3), "v1 - v2" : v1.subtract(v2), "v1 - v3" : v1.subtract(v3) }; r; /* returns: {"v1 + v3":"13:30:45-05:00", "v1 - v2":"PT14H20M20S", "v1 - v3":"11:30:45-05:00"} */
Comparison methods are available to compare values (less than, greater than, and so on) on the following duration, date, and dateTime objects:
The following comparison methods are available on xs.yearMonthDuration
objects:
The following are some simple examples using these methods:
const v1 = xs.yearMonthDuration("P3Y7M"); const v2 = xs.yearMonthDuration("P1Y4M"); const r = { "v1 lt v2" : v1.lt(v2), "v1 le v2" : v1.le(v2), "v1 gt v2" : v1.gt(v2), "v1 ge v2" : v1.ge(v2), "v1 eq v2" : v1.eq(v2), "v1 ne v2" : v1.ne(v2) }; r; /* returns: {"v1 lt v2":false, "v1 le v2":false, "v1 gt v2":true, "v1 ge v2":true, "v1 eq v2":false, "v1 ne v2":true} */
The following comparison methods are available on xs.dayTimeDuration
objects:
The following are some simple examples using these methods:
const v1 = xs.dayTimeDuration("P5DT4H"); const v2 = xs.dayTimeDuration("P1DT1H"); const r = { "v1 lt v2" : v1.lt(v2), "v1 le v2" : v1.le(v2), "v1 gt v2" : v1.gt(v2), "v1 ge v2" : v1.ge(v2), "v1 eq v2" : v1.eq(v2), "v1 ne v2" : v1.ne(v2) }; r; /* returns: {"v1 lt v2":false, "v1 le v2":false, "v1 gt v2":true, "v1 ge v2":true, "v1 eq v2":false, "v1 ne v2":true} */
The following comparison methods are available on xs.dateTime
objects:
The following are some simple examples using these methods:
const v1 = xs.dateTime(xs.date('2013-08-15'), xs.time('12:30:45-05:00')) const v2 = xs.dateTime(xs.date('2012-04-01'), xs.time('01:10:25-02:00')) const r = { "v1 lt v2" : v1.lt(v2), "v1 le v2" : v1.le(v2), "v1 gt v2" : v1.gt(v2), "v1 ge v2" : v1.ge(v2), "v1 eq v2" : v1.eq(v2), "v1 ne v2" : v1.ne(v2) }; r; /* returns: {"v1 lt v2":false, "v1 le v2":false, "v1 gt v2":true, "v1 ge v2":true, "v1 eq v2":false, "v1 ne v2":true} */
The following comparison methods are available on xs.date
objects:
The following are some simple examples using these methods:
const v1 = xs.date('2013-08-15'); const v2 = xs.date('2012-04-01'); const r = { "v1 lt v2" : v1.lt(v2), "v1 le v2" : v1.le(v2), "v1 gt v2" : v1.gt(v2), "v1 ge v2" : v1.ge(v2), "v1 eq v2" : v1.eq(v2), "v1 ne v2" : v1.ne(v2) }; r; /* returns: {"v1 lt v2":false, "v1 le v2":false, "v1 gt v2":true, "v1 ge v2":true, "v1 eq v2":false, "v1 ne v2":true} */
The following comparison methods are available on xs.time
objects:
The following are some simple examples using these methods:
const v1 = xs.time('12:30:45-05:00'); const v2 = xs.time('01:10:25-02:00'); const r = { "v1 lt v2" : v1.lt(v2), "v1 le v2" : v1.le(v2), "v1 gt v2" : v1.gt(v2), "v1 ge v2" : v1.ge(v2), "v1 eq v2" : v1.eq(v2), "v1 ne v2" : v1.ne(v2) }; r; /* returns: {"v1 lt v2":false, "v1 le v2":false, "v1 gt v2":true, "v1 ge v2":true, "v1 eq v2":false, "v1 ne v2":true} */
The following comparison methods are available on xs.gYearMonth
objects:
Method | Description |
---|---|
eq(xs. |
Equality comparison on xs.gYearMonth values. Returns a Boolean . |
ne(xs. |
Not equal to comparison on xs.gYearMonth values. Returns a Boolean . |
The following are some simple examples using these methods:
const v1 = xs.gYearMonth('2013-08'); const v2 = xs.gYearMonth('2012-04'); const r = { "v1 eq v2" : v1.eq(v2), "v1 ne v2" : v1.ne(v2) }; r; /* returns: {"v1 eq v2":false, "v1 ne v2":true} */
The following comparison methods are available on xs.gYear
objects:
Method | Description |
---|---|
eq(xs. |
Equality comparison on xs.gYear values. Returns a Boolean . |
ne(xs. |
Not equal to comparison on xs.gYear values. Returns a Boolean . |
The following are some simple examples using these methods:
const v1 = xs.gYear('2013'); const v2 = xs.gYear('2012'); const r = { "v1 eq v2" : v1.eq(v2), "v1 ne v2" : v1.ne(v2) }; r; /* returns: {"v1 eq v2":false, "v1 ne v2":true} */
The following comparison methods are available on xs.gMonthDay
objects:
Method | Description |
---|---|
eq(xs. |
Equality comparison on xs.xs.gMonthDay values. Returns a Boolean . |
ne(xs. |
Not equal to comparison on xs.xs.gMonthDay values. Returns a Boolean . |
The following are some simple examples using these methods:
const v1 = xs.gMonthDay('--08-20'); const v2 = xs.gMonthDay('--04-14'); const r = { "v1 eq v2" : v1.eq(v2), "v1 ne v2" : v1.ne(v2) }; r; /* returns: {"v1 eq v2":false, "v1 ne v2":true} */
The following comparison methods are available on xs.gMonth
objects:
Method | Description |
---|---|
eq(xs. |
Equality comparison on xs.gMonth values. Returns a Boolean . |
ne(xs. |
Not equal to comparison on xs.gMonth values. Returns a Boolean . |
The following are some simple examples using these methods:
const v1 = xs.gMonth('--08'); const v2 = xs.gMonth('--04'); const r = { "v1 eq v2" : v1.eq(v2), "v1 ne v2" : v1.ne(v2) }; r; /* returns: {"v1 eq v2":false, "v1 ne v2":true} */
The following comparison methods are available on xs.gDay
objects:
Method | Description |
---|---|
eq(xs. |
Equality comparison on xs.gDay values. Returns a Boolean . |
ne(xs. |
Not equal to comparison on xs.gDay values. Returns a Boolean . |
The following are some simple examples using these methods:
const v1 = xs.gDay('---08'); const v2 = xs.gDay('---04'); const r = { "v1 eq v2" : v1.eq(v2), "v1 ne v2" : v1.ne(v2) }; r; /* returns: {"v1 eq v2":false, "v1 ne v2":true} */
There are a large number of MarkLogic built-in functions available in JavaScript. In general, most functions available in XQuery have siblings that are available in JavaScript. For details on the MarkLogic functions available in JavaScript, see JavaScript Functions and Constructors.