Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- xquery version "3.0";
- import module namespace functx="http://www.functx.com";
- declare %private function local:object.cache($xml-fragment as item())
- {
- try
- {
- let $object-id := util:uuid()
- let $cache-collection := '/db/apps/chris/__object-cache/'
- let $cache-filename := $object-id || '.obj'
- let $cached-in := xmldb:store($cache-collection, $cache-filename, $xml-fragment)
- return
- (
- element cache
- {
- element object-id { $object-id },
- element collection { $cache-collection },
- element filename { $cache-filename },
- element resource { $cached-in },
- element cached { if(empty($cached-in)) then false() else true() }
- }
- )
- }
- catch *
- {
- ()
- }
- };
- declare %private function local:object.new.internals($xml-fragment, $cache-information)
- {
- map:entry("__created", util:system-dateTime()),
- map:entry("__id", $cache-information/object-id/text()),
- map:entry("__cache", $cache-information/resource/text()),
- map:entry("__cached", $cache-information/cached/text()),
- map:entry("__hash", util:hash($xml-fragment,'MD5')),
- map:entry("__object", $xml-fragment)
- };
- declare %private function local:object.new.methods()
- {
- map:entry
- (
- "valid()",
- (
- (: [1] METADATA :)
- element metadata
- {
- element description { 'Ensures that the internal hash matches that of the embedded object.' }
- },
- (: [2] IMPL :)
- function($map as map) as xs:boolean { $map("__hash") eq util:hash($map("__object"),'MD5') }
- )
- ),
- map:entry
- (
- "id()",
- (
- element metadata
- {
- element description { 'Returns the identifier for this object.' }
- },
- function($map as map) as xs:string { $map("__id") }
- )
- ),
- map:entry
- (
- "object()",
- (
- element metadata
- {
- element description { 'Returns the XML fragment representing this object.' }
- },
- function($map as map) as xs:string { $map("__object") }
- )
- ),
- map:entry
- (
- "transform()",
- (
- element metadata
- {
- element description { 'Returns the XML fragment representing this object.' }
- },
- function($map as map, $stylesheet as item(), $parameters as node()?) as xs:string
- { transform:transform($map("__object"),$stylesheet,$parameters) }
- )
- )
- };
- declare function local:object.new($xml-fragment as item())
- {
- let $clone := $xml-fragment (: fragment passed by value ? :)
- (: util:deep-copy($xml-fragment) :) (: TODO -- necessary? :)
- return map:new
- (
- (
- local:object.new.internals($clone, local:object.cache($clone)),
- local:object.new.methods(),
- local:object.build.properties($clone)
- )
- )
- };
- declare %private function local:object.build.properties($object)
- {
- for $child in $object/*
- return local:object.build.properties.from.children($object/*)
- };
- declare %private function local:object.build.properties.from.children($children)
- {
- if(empty($children))
- then ()
- else
- (
- for $child in $children
- return
- (
- local:object.build.property.map.entry($child),
- local:object.build.properties.from.children($child/*)
- )
- )
- };
- declare %private function local:object.build.property.map.entry($object)
- {
- let $object-metadata := local:object.build.property.metadata($object)
- return map:entry
- (
- $object-metadata[1],
- (
- (: [1] METADATA :)
- $object-metadata[2],
- (: [2] FUNCTIONS :)
- (
- (: [1] GETTER :)
- function($map as map, $prop-name as xs:string, $value as xs:boolean)
- {
- let $node :=
- util:node-by-id
- (
- $map("__object"),
- $map($prop-name)[1]/node-id/text()
- )
- return if($value)
- then $node/text()
- else $node
- }
- )
- )
- )
- };
- declare %private function local:object.build.property.metadata.local-name($object)
- {
- if($object/@name)
- then $object/@name/string()
- else
- (
- if($object/@type/string() eq 'object')
- then functx:substring-after-last(functx:path-to-node-with-pos($object), '/')
- else 'unknown'
- )
- };
- declare %private function local:object.build.property.metadata.full-name($object)
- {
- string-join(
- for $ancestor in $object/ancestor-or-self::*
- where util:node-id($ancestor) ne '1'
- return local:object.build.property.metadata.local-name($ancestor)
- ,'.')
- };
- declare %private function local:object.build.property.metadata($object)
- {
- local:object.build.property.metadata.full-name($object),
- element metadata
- {
- element type { $object/@type/string() },
- element node-id { util:node-id($object) },
- element xpath1 { util:node-xpath($object) },
- element xpath2 { functx:path-to-node-with-pos($object) }
- (:
- element parent-name { $parent-name },
- element parent-id { $parent-id },
- element functx
- {
- element path { functx:path-to-node($object) },
- element path-pos { functx:path-to-node-with-pos($object) },
- element distinct-paths
- {
- for $path in functx:distinct-element-paths($object)
- return element path { $path }
- },
- element distinct-names
- {
- for $name in functx:distinct-element-names($object)
- return element name { $name }
- },
- element max-depth { functx:max-depth($object) },
- element depth { functx:depth-of-node($object) }
- }
- :)
- }
- };
- declare function local:object.dispose($object)
- {
- ()
- };
- declare function local:object.get-value($object, $property-name)
- {
- local:object.get($object,$property-name,true())
- };
- declare function local:object.get-item($object, $property-name)
- {
- local:object.get($object,$property-name,false())
- };
- declare %private function local:object.get($object,$property-name,$value-only)
- {
- if(map:contains($object, $property-name))
- then $object($property-name)[2][1]($object,$property-name,$value-only)
- else error(QName('http://haptixgames.com/err', 'PropertyNotFound'), $property-name || ' not found.')
- };
- declare function local:object.call($object, $method-name)
- {
- local:object.call($object, $method-name, $object)
- };
- declare function local:object.call($object, $method-name, $arguments)
- {
- if(map:contains($object, $method-name))
- then $object($method-name)[2]($arguments)
- else error(QName('http://haptixgames.com/err', 'MethodNotFound'), $method-name || ' not found.')
- };
- declare function local:object.inspect($object)
- {
- element object.inspect
- {
- local:object.inspect.internals($object),
- local:object.inspect.methods($object),
- local:object.inspect.properties($object)
- }
- };
- declare %private function local:object.inspect.internals($object)
- {
- element internals
- {
- for $key in map:keys($object)
- where starts-with($key, "__") and $key ne '__object'
- order by $key ascending
- return element { replace($key, "__", "") } { $object($key) }
- }
- };
- declare %private function local:object.inspect.methods($object)
- {
- element methods
- {
- for $key in map:keys($object)
- let $method := $object($key)
- where ends-with($key, "()")
- order by $key ascending
- return
- (
- element method
- {
- element name { $key },
- $object($key)[1],
- element signature { inspect:inspect-function($method[2])/* }
- }
- )
- }
- };
- declare %private function local:object.inspect.properties($object)
- {
- element properties
- {
- for $key in map:keys($object)
- let $property := $object($key)
- where not(starts-with($key, "__")) and not(ends-with($key, "()"))
- order by $property[1]/node-id/text() ascending
- return
- (
- element property
- {
- element name { $key },
- $property[1]
- }
- )
- }
- };
- let $xml :=
- <json type="object">
- <pair name="firstName" type="string">John</pair>
- <pair name="lastName" type="string">Smith</pair>
- <pair name="age" type="number">25</pair>
- <pair name="address" type="object">
- <!-- address.streetAddress -->
- <pair name="streetAddress" type="string">21 2nd Street</pair>
- <pair name="city" type="string">New York</pair>
- <pair name="state" type="string">NY</pair>
- <pair name="postalCode" type="number">10021</pair>
- <pair name="alive" type="boolean">true</pair>
- <!--<pair name="empty" type="null"/></pair> BROKEN -->
- </pair>
- <!-- phoneNumbers -->
- <pair name="phoneNumbers" type="array">
- <item type="object">
- <pair name="type" type="string">home</pair>
- <pair name="number" type="string">212 555-1234</pair>
- </item>
- <!-- phoneNumbers[2] -->
- <item type="object">
- <!-- phoneNumbers[2].type -->
- <pair name="type" type="string">fax</pair>
- <!-- phoneNumbers[2].number -->
- <pair name="number" type="string">646 555-4567</pair>
- </item>
- </pair>
- </json>
- let $object := local:object.new($xml)
- let $xml := <nothing><more/><to/><see/><here/></nothing>
- return
- (
- local:object.inspect($object),
- local:object.get-item($object, "address"),
- local:object.get-item($object, "firstName"),
- local:object.get-value($object, "lastName"),
- local:object.get-value($object, "address.city"),
- local:object.get-value($object, "phoneNumbers.item[2].number"),
- local:object.call($object, "valid()"),
- local:object.call($object, "id()")
- )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement