Reputation: 57
We are using the MarkLogic 9.0.5 and the DHF 3.0 and we are trying to harmonize multiple source documents into a denormalized form. However, we can't get the xml form right.
Let us say we have a source document for family and one each for family-member. Now, we want to generate a harmonized entity something like this:
<envelope>
<header></header>
<instance>
<family>
<name>Paulsen</name>
<family-member>
<name>John</name>
<age>54</age>
</family-member>
<family-member>
<name>Clarice</name>
<age>38</age>
</family-member>
</family>
</instance>
</envelope>
However, the new DHF structure forces us to use json object map to generate the code but any way we put the data into the object we won't get it out like the above. For instance:
declare function plugin:extract-instance-family
$source as node()?,
$options as map:map
) as map:map
let $name := get-family-name()
let $family-member := (<family-member>
<name>get-name()</name>
<age>get-age()</age>
</family-member>,
<family-member>
<name>get-name()</name>
<age>get-age()</age>
</family-member>)
let $model :=
json:object()
=>map:with('name', $name)
=>map:with('family-member', '$family-member')
return $model
};
results in some xml like:
<envelope>
<header></header>
<instance>
<family>
<name>Paulsen</name>
<family-member>
<family-member>
<name>John</name>
<age>54</age>
</family-member>
</family-member>
<family-member>
<family-member>
<name>Clarice</name>
<age>38</age>
</family-member>
</family-member>
</instance>
</envelope>
This contains each family node twice. Any suggestions on how to resolve this?
PS I have also tried passing nested json-objects as arguments, but apparently that results in errors in the dhf-flows:
let $family-member := json-object()
=> map:with('family-member', 'stuff')
Upvotes: 1
Views: 101
Reputation: 256
There is a reasoning behind this behavior. This is following a pattern that is being used in MarkLogic Entity Services. You can read more about the benefits of using entity modeling here: http://docs.marklogic.com/guide/entity-services/intro#id_23284.
It may help to adjust your code so the element names don't collide and make it clear that the second layer is describing an entity type, unlike the first layer that is describing a property name to the top-level entity.
E.g.,
declare function plugin:extract-instance-family-type
$source as node()?,
$options as map:map
) as map:map
let $name := get-family-name()
let $family-member := (<family-member-type>
<name>get-name()</name>
<age>get-age()</age>
</family-member>,
<family-member>
<name>get-name()</name>
<age>get-age()</age>
</family-member-type>)
let $model :=
json:object()
=>map:with('name', $name)
=>map:with('family-member', '$family-member')
return $model
};
In this case, you could consider the situation where you may want to extract data to a Java program. The top-level family-type entity would map to a Family Java class and the family-member element familyMember field of the class and finally, family-member-type would map to a FamilyMember class and its associated fields.
Also, if you plan to consume the data as JSON, I would go even further and recommend the convention of making Entity types TitleCase and properties camelCase. (FamilyType, familyMember, FamilyMemberType).
Upvotes: 1