Boost ptree top level array - c++

I would like to have write_json output a top level array, something to the effect of:
[{...},{...},{...},...,{...}]
But when I pass a list to write_json, it converts to a json full of blank keys.
{"":{...},"":{...},"":{...},..."":{...}}
Using add_child actually respects the array and gives me the closest thing of:
{"Some Key":[{...},{...},{...},...,{...}]}
But that's still not what I want.
Any idea how to make that array top level?

Boost does not have a JSON library (nor does it have an XML library). It has a Property Tree library (which happens to include a JSON compatible representation).
The limitations you run into are perfectly clearly documented right there: http://www.boost.org/doc/libs/1_62_0/doc/html/property_tree/parsers.html#property_tree.parsers.json_parser
The property tree dataset is not typed, and does not support arrays as such. Thus, the following JSON / property tree mapping is used:
JSON objects are mapped to nodes. Each property is a child node.
JSON arrays are mapped to nodes. Each element is a child node with an empty name. If a node has both named and unnamed child nodes, it cannot be mapped to a JSON representation.
JSON values are mapped to nodes containing the value. However, all type information is lost; numbers, as well as the literals "null", "true" and "false" are simply mapped to their string form.
Property tree nodes containing both child nodes and data cannot be mapped.
JSON round-trips, except for the type information loss.
It goes on to show an example of EXACTLY what you run into.

Related

How can I use computed variables in key:value list in AppleScript

How to generate an Array (list) like
set myList to {key1:"foo1", key2:"foo2"}
I would like to increment keys in a repeat-loop.
This is what I have tested so far:
-- hardcoded key:value pair works fine
set mySimpleList to {key1:"foo1"} --> result OK: {key1:"foo1"}
-- generated value works too
set i to 1
set myValue to "foo" & i
set myGoodList to {key1:myValue} --> result OK: {key1:"foo1"}
-- generated key fails
set i to 1
set k to "key" & i --> "key1"
set myValue to "foo" & i
set myFailedList to {k:myValue} --> failed: {k:"foo1"}
Where ist the error? Are there any workarounds?
Records are AppleScript's half-arsed version of what other languages refer to as dictionaries or associative arrays (although these are slightly different entities, but the minutiae aren't significant for now). Unlike dictionaries, which have accessible keys and values one can operate on, records have inaccessible keys (called properties) and accessible values for a known, named property.
Values in the record are read by way of syntax that takes the form <property> of <record>. Because the property is an identifier, and not a string, it can't be substituted out for a proxy, such as a variable, since this is just another identifier that will be treated as a property reference that likely doesn't exist in the record.
Your easiest solution is to use paired lists of the form {<key>, <value>}. Lists are easy-to-use if not especially efficient at what they do. It does mean you'd have to write your own handlers for, say, finding a specific value given a key, but that's reasonably straight forward.
Of course, since you want keys that increment in value, then that's exactly what a straightforward list is: indexed values ordered by integer keys that start at 1 and increment with each element to its right.
NSDictionary is an AppleScriptObjC class that allows conversion of records into dictionaries. They are represented as an opaque reference type to an Objective-C object, so it lacks the visual form of records. But it allows manipulation of keys and values, but the trade off is the need to convert back and forth between the opaque type and an AppleScript type.
Technically, records's properties are compiled into the script, so they aren't something that one would expect to generate on-the-fly during runtime. If you really really want to, you can actually do this, but its value might be mitigated by the work involved:
set entries to {"key1", "foo1", "key2", "foo2", ...}
set _Ref to {«class usrf»:entries}'s contents as anything
--> {key1:"foo1", key2:"foo2", ...}
Unwrapping (serialising) a record is irksome, and relies on the clipboard, which isn't ideal:
set the clipboard to _Ref
get the clipboard as list
--> {"key1", "foo1", "key2", "foo2", ...}
I don't recommend doing any of this, by the way, but it's there if you want to.

set `exclude_from_indexes` for Array datatype

I'm storing a list of strings using Array datatype in Datastore(e.g. ["name1", "name2", ...]). As the list grows, I find myself unable to upsert the entry.
INVALID_ARGUMENT: Too many indexed properties
According to https://cloud.google.com/datastore/docs/concepts/entities#array, even if I set the property to be exclude_from_indexes, it gets ignored. The datastore web UI also doesn't have an Index checkmark for me to uncheck.
So the only option I came up with is to convert the Array into a String type and parse to a JSON Object every time I read from DB, and write back stringified.
Was wondering if this is the right approach or if there are better ways to do this I'm not aware of.
Thanks
You should set the exclude_from_indexes on each value of the array. That is what "For a property to be unindexed, the exclude_from_indexes field of Value must be set to true." means.

C++: Reading XML files using with 'preserveWhitespace' enabled

I'm using IXMLDOMNode::get_childNodes() with preserveWhiteSpace set to true, which causes it to treat carriage returns between elements as nodes. In my child list, I get a few nodes with the name #text.
Is there any way to remove these nodes from my list? I have a CComPtr<IXMLDOMNodeList> object, and there are no members that allow me to add/remove to it.
I'm thinking of using selectNodes() instead, and passing an expression that ignores all nodes with the name #text. Would this be possible?
I just tried selectNodes() and passed the expression //*[not(self::#text)], but that doesn't seem to work.

Creating IXMLDOMnode from string

I have a string which contains the XML representation of an XML node which I intend to insert in a XML document loaded in memory. The XML string (of node)is something like this:
<ns1:Feature name=\"PageSize\">\
<ns1:Option name=\"A4\" />\
</ns1:Feature>
So, it has got namespace for the tag names as well.
Is there a way I can achieve this?
I tried to user XMLDomNode->put_text(), but it does not work as it replaces the "<" and ">" chars by their text representations (< etc.)
I was wondering if loading the string buffer in a separate in-memory XML document and then getting the node pointer from there will work on my original document. But again, not sure if the XMLDOMnodes are transferable within documents.
I solved this myself using the 2nd approach:
1) Create an in-memory xml document based on IXMLDOMDocument3 interface and load the xml string in there.
2) Select the node you require using the selectNode() method.
3) Now go back to your orinial xml document where you want the node placed and load it again as a IXMLDOMDocument3 interface.
4) Use the importNode() method of IXMLDOMDocument3 from step 3 to clone the node obtained in step 2.
5) You can now use the cloned node to do an appendChild() to the original xml.

DynamoDB create index on map or list type

I'm trying to add an index to an attribute inside of a map object in DynamoDB and can't seem to find a way to do so. Is this something that is supported or are indexes really only allowed on scalar values? The documentation around this seems to be quite sparse. I'm hoping that the indexing functionality is similar to MongoDB but so far the approaches I've taken of referencing the attribute to index using dot syntax has not been successful. Any help or additional info that can be provided is appreciated.
Indexes can be built only on top-level JSON attributes. In addition, range keys must be scalar values in DynamoDB (one of String, Number, Binary, or Boolean).
From http://aws.amazon.com/dynamodb/faqs/:
Q: Is querying JSON data in DynamoDB any different?
No. You can create a Global Secondary Index or Local Secondary Index
on any top-level JSON element. For example, suppose you stored a JSON
document that contained the following information about a person:
First Name, Last Name, Zip Code, and a list of all of their friends.
First Name, Last Name and Zip code would be top-level JSON elements.
You could create an index to let you query based on First Name, Last
Name, or Zip Code. The list of friends is not a top-level element,
therefore you cannot index the list of friends. For more information
on Global Secondary Indexing and its query capabilities, see the
Secondary Indexes section in this FAQ.
Q: What data types can be indexed?
All scalar data types (Number, String, Binary, and Boolean) can be
used for the range key element of the local secondary index key. Set,
list, and map types cannot be indexed.
I have tried doing hash(str(object)) while I store the object separately. This hash gives me an integer(Number) and I am able to use a secondary index on it. Below is a sample in python, it is important to use a hash function which generates the same hash key every time for the value. So I am using sha1.
# Generate a small integer hash:
import hashlib
def hash_8_digits(source):
return int(hashlib.sha1(source.encode()).hexdigest(), 16) % (10 ** 8)
The idea is to keep the entire object small while still the entity intact. i.e. rather than serializing and storing the object as string and changing whole way the object is used I am storing a smaller hash value along with the actual list or map.