Ranjan Sarma
Ranjan Sarma

Reputation: 1595

How to use or implement arrays in XQuery?

Is there any built in support for array in XQuery? For example, if we want to implement the simple java program in xquery how we would do it:

(I am not asking to translate the entire program into xquery, but just asking how to implement the array in line number 2 of the below code to xquery? I am using marklogic / xdmp functions also).

java.lang.String test = new String("Hello XQuery");
char[] characters = test.toCharArray();

for(int i = 0; i<characters.length; i++) {
    if(character[i] == (char)13) { 
        character[i] = (char) 0x00;
    }
}

Legend:

hex 0x00 dec 0 : null
hex 0x0d dec 13: carriage return
hex 0x0a dec 10: line feed
hex 0x20 dec 22: dquote

Upvotes: 4

Views: 14854

Answers (7)

amix
amix

Reputation: 133

Since the question "How to use or implement arrays in XQuery?" is being held generic (and thus shows up in search results on this topic), I would like to add a generic answer for future reference (making it a Community Wiki, so others may expand):

As Christian Grün has already hinted at, with XQuery 3.1 XQuery got a native array datatype, which is a subtype of the function datatype.

Since an array is a 'ordered list of values' and an XPath/XQuery sequence is as well, the first question, which may arise, is: "What's the difference?" The answer is simple: a sequence can not contain another sequence. All sequences are automatically flattened. Not so an array, which can be an array of arrays. Just like sequences, arrays in XQuery can also have any mix of any other datatype.

The native XQuery array datatype can be expressed in either of two ways: As [] or via array {}. The difference being, that, when using the former constructor, a comma is being considered a 'hard' comma, meaning that the following array consists of two members:

[ ("apples", "oranges"), "plums" ]

while the following will consist of three members:

array { ("apples", "oranges"), "plums" }

which means, that the array expression within curly braces is resolved to a flat sequence first, and then memberized into an array.

Since Array is a subtype of function, an array can be thought of as an anonymous function, that takes a single parameter, the numeric index. To get the third member of an array, named $foo, we thus can write:

$foo(3)

If an array contains another array as a member you can chain the function calls together, as in:

$foo(3)(5)

Along with the array datatype, special operators have been added, which make it easy to look up the values of an array. One such operator (also used by the new Map datatype) is the question mark followed by an integer (or an expression that evaluates to zero or more integers).

$foo?(3)

would, again, return the third member within the array, while

$foo?(3, 6)

would return the members 3 and 6.

The parenthesis can be left out, when working with literal integers. However, the parens are needed, to form the lookup index from a dynamic expression, like in:

$foo?(3 to 6)

here, the expression in the parens gets evaluated to a sequence of integers and thus the expression would return a sequence of all members from index position 3 to index position 6.

The asterisk * is used as wildcard operator. The expression

$foo?*

will return a sequence of all items in the array. Again, chaining is possible:

$foo?3?5

matches the previos example of $foo(3)(5).

More in-depth information can be found in the official spec: XML Path Language (XPath) 3.1 / 3.11.2 Arrays

Also, a new set of functions, specific to arrays, has been implemented. These functions resinde in the namespace http://www.w3.org/2005/xpath-functions/array, which, conventionally, is being prefixed with array and can be found referenced in here: XPath and XQuery Functions and Operators 3.1 / 17.3 Functions that Operate on Arrays

Upvotes: 1

Schinski
Schinski

Reputation: 1

You can construct an array like this:

$myArray = tokenize('a b c d e f g', '\s')
// $myArray[3] -> c 

Please note that the first index of this pseudo-array is 1 not 0!

Upvotes: 0

Christian Gr&#252;n
Christian Gr&#252;n

Reputation: 6219

A little outlook: XQuery 3.1 will provide native support for arrays. See http://www.w3.org/TR/xquery-31/ for more details.

Upvotes: 0

grtjn
grtjn

Reputation: 20414

XQuery has built-in support for sequences. The function tokenize() (as suggested by @harish.ray) returns a sequence. You can also construct one yourself using braces and commas:

let $mysequence = (1, 2, 3, 4)

Sequences are ordered lists, so you can rely on that. That is slightly different from a node-set returned from an XPath, those usually are document-ordered.

On a side mark: actually, everything in XQuery is either a node-set or a sequence. Even if a function is declared to return one string or int, you can treat that returned value as if it is a sequence of one item. No explicit casting is necessary, for which there are no constructs in XQuery anyhow. Functions like fn:exists() and fn:empty() always work.

HTH!

Upvotes: 4

Michael Kay
Michael Kay

Reputation: 163262

The problem with converting your sample code to XQuery is not the absence of support for arrays, but the fact that x00 is not a valid character in XML. If it weren't for this problem, you could express your query with the simple function call:

translate($input, '&#x13;', '&#x00;')

Now, you could argue that's cheating, it just happens so that there's a function that does exactly what you are trying to do by hand. But if this function didn't exist, you could program it in XQuery: there are sufficient primitives available for strings to allow you to manipulate them any way you want. If you need to (and it's rarely necessary) you can convert a string to a sequence of integers using the function string-to-codepoints(), and then take advantage of all the XQuery facilities for manipulating sequences.

The lesson is, when you use a declarative language like XQuery or XSLT, don't try to use the same low-level programming techniques you were forced to use in more primitive languages. There's usually a much more direct way of expressing the problem.

Upvotes: 6

mblakele
mblakele

Reputation: 7840

Just for fun, here's how I would do this in XQuery if fn:translate did not exist. I think Michael Kay's suggestion would end up looking similar.

let $test := "Hello XQuery"
return codepoints-to-string(
  for $c in string-to-codepoints($test)
  return if ($c eq 32) then 44 else $c)

Note that I changed the transformation because of the problem he pointed: 0 is not a legal codepoint. So instead I translated spaces to commas.

With MarkLogic, another option is to use http://docs.marklogic.com/json:array and its associated functions. The json:set-item-at function would allow coding in a vaguely imperative style. Coding both variations might be a good learning exercise.

Upvotes: 2

Harish Raj
Harish Raj

Reputation: 1575

There are two ways to do this.

  • Firstly you can create an XmlResults object using XmlManager.createResults(), and use XmlResults.add() to add your strings to this. You can then use the XmlResults object to set the value of a variable in XmlQueryContext, which can be used in your query.

    Example:

    XmlResults values = XMLManager.createResults();
    values.add(new XmlValue("value1"));
    values.add(new XmlValue("value2"));
    XmlQueryContext.setVariableValue("files", values);
    
  • The alternative is to split the string in XQuery. You can do this using the tokenize() function, which works using a regular expression to match the string separator.

    http://www.w3.org/TR/xpath-functions/#func-tokenize

Thanks.

Upvotes: 0

Related Questions