New to JSONIQ,and using zorba what I want to do so far is to extract some information from an indexed object in an object array in JSONIQ. Here's the code so far.
jsoniq version "1.0";
let $bstore:={
"bookstore":
{
"book":[
{
"category":"cooking",
"title":"Everyday Italian",
"author":"Giada De Laurentiis",
"year":"2005",
"price":"30.00"
},
{
"category":"web",
"title":"XQuery Kick Start",
"author":["James McGovern","Per Bothner","Kurt Cagle","James Linn","Vaidyanathan Nagarajan"],
"year":"2003",
"price":"49.99"
}
]
}
}
for $o in $bstore.bookstore
let $a:=$o.book
return $a.title
What I'm trying to do is to return the title,author,and price of the books.
I am able to return the array but whenever I type the index.
let $a:=$o.book[1].title
return $a
I get no results. My expected output would be
Everyday Italian
Any help would be much appreciated.
Array lookup in JSONiq is done with double square brackets, like so:
let $a:=$o.book[[1]].title
return $a
Note, however, that the try.zorba.io page is based on an earlier version of Zorba (2.9) that doesn't support the latest version of JSONiq (it should get upgraded at some point). In this earlier version, array lookup used to be done overloading function call syntax:
let $a:=$o.book(1).title
return $a
If you want to use the stable version of JSONiq with its up-to-date syntax, you can download Zorba 3.0 and execute queries locally.
The semantics of [] with simple square brackets is that it filters through a sequence, either with a position or with a boolean filter, for example:
(1, 2, 3, 4)[2]
returns 2.
An array is different from a sequence. An array can be seen as a "boxed" sequence, i.e., (1, 2, 3, 4) is a sequence of four items, but [1, 2, 3, 4] is a sequence of just one item: the array containing the nested 1, 2, 3 and 4.
You can convert an array to a sequence with $o.book[] if needed ($o.book() with Zorba 2.9). And you can "wrap" a sequence back into an array with [ $sequence ]. It is a bit like opening, or closing a box.
Only arrays can recursively nest, e.g., [ [1, 2], [3, 4]] has two levels of nesting, exactly as would be expected of JSON arrays. Sequences however do not nest, i.e., ((1, 2), (3, 4) is the same as the flat sequence (1, 2, 3, 4), with zero levels of nesting. Sequences of items are the primary citizen of JSONiq, and are compatible with a streaming execution (for example, filtering a sequence of millions of objects without actually materializing it).
I planned initially to iterate over an array of objects to print out the data within the objects. For JSONIQ, I discovered that I needed to parenthesize the array name which is book() in this case.
My code below should iterate over, the title, the author, and the price of the book.
jsoniq version "1.0";
let $bstore:={
"bookstore":
{
"book":[
{
"category":"cooking",
"title":"Everyday Italian",
"author":"Giada De Laurentiis",
"year":"2005",
"price":"30.00"
},
{
"category":"web",
"title":"XQuery Kick Start",
"author":["James McGovern","Per Bothner","Kurt Cagle","James Linn","Vaidyanathan Nagarajan"],
"year":"2003",
"price":"49.99"
}
]
}
}
for $o in $bstore.bookstore.book()
return
{
"title":$o.title,
"author":$o.author,
"price":$o.price
}
The code can be tested at Zorba.
The output is as shown below:
{ "title" : "Everyday Italian", "author" : "Giada De Laurentiis", "price" : "30.00" }{ "title" : "XQuery Kick Start", "author" : [ "James McGovern", "Per Bothner", "Kurt Cagle", "James Linn", "Vaidyanathan Nagarajan" ], "price" : "49.99" }
Related
I have a json file looking like this:
{
"parents": [{
// array of objects
}],
"modules": {
"a": 1,
"b": 2
}
}
I want to remove they key b of the object modules.
I am running this command: jq "with_entries(.value |= del(.b))"
But this fails when the parents array is present. I get
Cannot index array with string "b"
How can I make the command ignore the parents array and only work on the modules object?
Your idea was right, but you missed the selecting the object desired inside with_entries(), hence your delete operation was attempted on all the objects in your JSON.
Since the parents record is an array type and not an object , the del function throws out an error that its not able to index the array with the given name. You need to do
with_entries( select(.key == "modules").value |= del(.b) )
The select() function filters that object keyed by name "modules" and applies the delete action on that object alone.
jq-play snippet
I'm forming an xml whose snippet is -
<cache-properties>
<list-cache-hit-rate>
<units>hits/sec</units>
<value>1.5308452E6</value>
</list-cache-hit-rate>
<list-cache-miss-rate>
<units>misses/sec</units>
<value>25422.167</value>
</list-cache-miss-rate>
<compressed-tree-cache-hit-rate>
<units>hits/sec</units>
<value>970.2339</value>
Notice the value 1.5308452E6 is big enough that the values are stored as exponent while performing fn:sum() behind the scene.
Later, I'm converting the xml to json by the following function -
let $arr := json:to-array(local:tojson($data))
return (($data))
and value converted looks like this -
cache-properties": {
"list-cache-hit-rate": {
"units": "hits/sec",
"value": 1.5308452E6
},
"list-cache-miss-rate": {
"units": "misses/sec",
"value": "25422.167"
},
"compressed-tree-cache-hit-rate": {
"units": "hits/sec",
"value": "970.2339"
},
Notice the values are enclosed in quotes except 1.5308452E6 this value. This is not in quotes. What correction is needed here ? Or is this correct? I'd rather have all values in quotes. This is my custom transform function-
declare function local:tojson($func){
let $custom := let $config := json:config("custom")
let $_ := map:put( $config, "whitespace", "ignore" )
let $_ := map:put( $config, "array-element-names", "Video" )
return $config
return json:transform-to-json($func,$custom)
};
Take a look at the xml schema. Your snippets appear to be similar or identical to marklogic system status xml schema however you mention 'fn:sum in the background' so Im guessing you have applied a transformation which has changed the xsd type.
The json transformation code uses the XSD type if in scope to determine the typed output in JSON (for XML numeric types). Also if the number is 'too large' it can convert to string to avoid JavaScript issue.
( it basically uses fn:data(value) to convert )
If needed you can either force a string type onto your xml, or you can specialize the transformation by overriding one of the json-custom: primitives in json/custom.xqy by supplying the appropriate mapping in the config. Look into the source for the full list of overridable functions. They are not fully documented as they are not with full generality in mind and may not be obvious, easy or possibly to change behaviour in every conceivable way.
The strategies are to either
Use an XML with schema in scope that types atomic values explicitly (in your case as xs:string),
Override one of the low level functions in custom.xqy
Convert the JSON by post-processing and 'stringify' the desired elements
Roll your own (not too difficult with the samples show)
All of the above
I have gone through most of the JSONPath documentations out there and they all explain that the script filters such as $.items[(#.length - 1)] only applies to an array and not to a JSON object. This means that the path would work for the first JSON object below and not for the second one:
1:
{
"items": [
1,
2
]
}
2:
{
"items": {
"item1": 1,
"item2": 2
}
}
Can anyone confirm this? Also, if I am correct, is there a logical reason for this behavior? I can imagine that such a path could have been allowed to return the same value (2) in both cases.
I need to create a method that takes a list of lists (like [ [2,3,] , [4,5] ]) and returns something like [2,3,4,5]. I can work out the logic but I dont know how to define the method in SML. I tried this but it does not compile
fun appendall(l:list list):list = ...
Take a look at the concat function from the List libary.
Moscow ML version 2.01 (January 2004)
Enter `quit();' to quit.
- load "List";
> val it = () : unit
- List.concat [[1,2],[3,4],[5,6]];
> val it = [1, 2, 3, 4, 5, 6] : int list
- quit();
An alternative solution could be to use List.foldr
val concat = List.foldr op# [];
Or you could just write it plain as an recursive function
fun concat2 [] = []
| concat2 (x::xs) = x # concat2 xs
Hope this helps you.
Looks like you've just got your types wrong. A list has to be a list of something (e.g. an int list). If the type of the contents is irrelevant, you can use a type variable 'a instead of a concrete type (so in your case, an 'a list and an 'a list list).
However, you almost never need type declarations in ML. Just write your function without them, and the compiler will be able to infer the types of the variables from the operations you're performing on them.
I'm writing an application in Flex / ActionScript and have a number of class member variables of type Array storing data.
My question is: what's the "best" way to clear out an Array object?
I noticed the ArrayCollection class has a function removeAll() which does this, but the basic Array class does not. Some possibilities I've considered are:
Iterating through the array, calling pop or shift on each element
Setting the array length to 0
Setting the member variable to a "new Array()" or "[]"
I'd say:
myArray = [ ];
That's explicit, short, and makes good use of the VM's garbage collector.
Your first alternative runs a lot of interpreted code to get the same result.
I don't know that the second does what you want; if it does, it's hacky, unclear.
The "new Array()" variant of the third alternative is just wordy, offering no advantage over an array literal. If you also write JS and use JSLint, you'll get yelled at for not using the array literal form.
I'm afraid to say but Warren Young is wrong when he said that setting the myArray = [] cause the garbage collector to pick up the array.
as you have the ability to add a reference to itself within itself, and therefore would never be collected and using up memory, especially if the array has some Sprites in the array, as they too would have the array references them and they too would never be collected.
Sly_cardinal and Richard Szalay are 100% correct. but the length parameter is not needed in Richard's.
To totally clear the array and make sure its collected by garbage then
myArray.splice(0);
myArray = null;
It depends on your context. While using Mr. Young's answer is often the most correct way to do things, it will not always work, especially if you have two variables pointing to the same array:
var foo:Array
var bar:Array
foo = bar = [ 1, 2, 3 ];
bar = [];
trace( foo ); // 1,2,3
On the other hand, if you actually empty the array manually:
var foo:Array
var bar:Array
foo = bar = [ 1, 2, 3 ];
var l:int = bar.length; // get the length FIRST!
// Otherwise bar.length will change
// while you iterate!
for( var i:int = 0; i < l; i++ )
{
bar.shift();
}
trace( foo ); // does not trace anything
If you can modify the array reference, then I would go with Warren's answer. If you need to modify the existing instance, you can also use Array.splice:
var arr : Array = [1, 2, 3, 4, 5];
arr.splice(0, arr.length);
According to this test the best way is to set length = 0