<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><id>tag:blogger.com,1999:blog-7604112102413778067</id><updated>2015-09-17T01:52:17.261-06:00</updated><category term="MarkLogic" /><category term="xQuery" /><category term="XQuery 3.0" /><category term="MarkLogic 6" /><category term="performance" /><category term="XML" /><category term="memory" /><category term="xpath" /><category term="Aggregate User Defined Functions" /><category term="Coding by Superstition" /><category term="Ruby on Rails" /><category term="XPath 3.0" /><category term="cts:search" /><category term="framework" /><category term="map:map" /><category term="try catch" /><category term="Erlang" /><category term="Inline Functions" /><category term="Mongoid" /><category term="Ruby" /><category term="XSL" /><category term="casting" /><category term="fn:function-arity" /><category term="fn:function-name" /><category term="java" /><category term="looping" /><category term="sliding window" /><category term="testing" /><category term="tumbling window" /><category term="C/C++" /><category term="Carrot" /><category term="Clark Notation" /><category term="Dynamic Function Calls" /><category term="HTML" /><category term="Higher Order Functions" /><category term="MarkLogic 7" /><category term="Metaprogramming" /><category term="Rake" /><category term="SAX" /><category term="Search" /><category term="Semantic" /><category term="Singleton" /><category term="Switch Case Expression" /><category term="XQUF" /><category term="XQuery hardening" /><category term="XQuery injection" /><category term="XSLT" /><category term="Xque" /><category term="aliases" /><category term="boolean" /><category term="code coverage" /><category term="copy" /><category term="cts:document-fragment-query" /><category term="cts:query" /><category term="cts:uris" /><category term="cts:word-query" /><category term="dateTime" /><category term="default for external variables" /><category term="design patterns" /><category term="empty" /><category term="empty-sequence" /><category term="encapsulation" /><category term="error handling" /><category term="except" /><category term="exists" /><category term="external variables" /><category term="fn:analyze-string" /><category term="fn:current-dateTime" /><category term="fn:data" /><category term="fn:doc-available" /><category term="fn:function-lookup" /><category term="fn:generate-id" /><category term="fn:has-children" /><category term="fn:head" /><category term="fn:innermost" /><category term="fn:node-name" /><category term="fn:outermost" /><category term="fn:path" /><category term="fn:subsequence" /><category term="fn:tail" /><category term="functional programming" /><category term="git" /><category term="government" /><category term="hashing" /><category term="i18n" /><category term="instance of" /><category term="intersect" /><category term="library module" /><category term="map operator" /><category term="memorization" /><category term="microdata" /><category term="mvc" /><category term="non-ob" /><category term="object-oriented programming" /><category term="plugin" /><category term="politics" /><category term="procedural programming" /><category term="prof:value" /><category term="programming" /><category term="programming languages" /><category term="reform" /><category term="regular expressions" /><category term="security" /><category term="sftp" /><category term="sha1" /><category term="software" /><category term="ssh" /><category term="static checking" /><category term="synonym" /><category term="technology" /><category term="transform XML" /><category term="transform statement" /><category term="typeswitch" /><category term="union" /><category term="unique ids" /><category term="unobtrusive XQuery" /><category term="unordered expression" /><category term="upgrade path" /><category term="validate lax" /><category term="web IDE" /><category term="xdmp:copy-on-validate" /><category term="xdmp:describe" /><category term="xdmp:eval" /><category term="xdmp:from-json" /><category term="xdmp:functions" /><category term="xdmp:get-server-field" /><category term="xdmp:invoke" /><category term="xdmp:request" /><category term="xdmp:set" /><category term="xdmp:set-server-field" /><category term="xdmp:sha1" /><category term="xqmvc" /><title type="text">The Max Dew Point</title><subtitle type="html">This is where I share little pieces of information I discover in my exploration of software development.</subtitle><link rel="alternate" type="text/html" href="http://maxdewpoint.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default?start-index=26&amp;max-results=25&amp;redirect=false" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>62</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/blogspot/tDYaS" /><feedburner:info uri="blogspot/tdyas" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-2285945151343226641</id><published>2014-05-25T06:53:00.003-06:00</published><updated>2014-05-25T07:21:17.953-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Aggregate User Defined Functions" /><category scheme="http://www.blogger.com/atom/ns#" term="dateTime" /><category scheme="http://www.blogger.com/atom/ns#" term="map:map" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic" /><title type="text">Revisiting MarkLogic Aggregate User Defined Functions</title><content type="html">So I figure it has been long enough since my last blog post and it is about time that I post something. It this blog post I'm going to revisit User Defined Functions in MarkLogic. To be completely honest, &lt;a href="http://maxdewpoint.blogspot.com/2012/09/my-first-marklogic-aggregate-user.html"&gt;my first try at a UDF&lt;/a&gt; proved that I could write one, but the end result was rather lame. In fact, if you go back and look at you'll see that the native code didn't do anything that couldn't be out performed, or at least matched, by XQuery code. &lt;br /&gt;&lt;br /&gt;So for my second attempt I thought I'd do something that would provide more value. That is when I thought that a good use would be to bucket values in a map. Using my first UDF as a starting point I decided to write a UDF that would bucket values based off of a regular expression. The key in the map will be the matching portion of the regular expression, while the values will be the strings that share the same string matching the regular expression. For example, if you passed the regular expression "^.", it will group the values in a map by the first character.&lt;br /&gt;&lt;br /&gt;Before going any farther, if you aren't familiar with UDFs in MarkLogic and how they work I encourage you to read Dave Cassel's &lt;a href="http://blog.davidcassel.net/2012/09/a-mapreduce-aggregation-function-in-marklogic-6/"&gt;blog post&lt;/a&gt; on the matter. He provides a clear view of what is going on behind the scenes.&lt;br /&gt;&lt;br /&gt;Since this works with regular expressions as well, I had a good start already in from my first attempt. Just as before, I read the first argument passed and compile a regular expression with it.&lt;br /&gt;&lt;div class="gistLoad" data-id="381af8580143f4c58f6d" id="gist-381af8580143f4c58f6d" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="C++ start MarkLogic UDF function"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="C++"/&gt;&lt;br /&gt;&lt;![CDATA[ void BucketeerRegex:: start(Sequence&amp; arg, Reporter&amp; reporter) { overflow_bucket = "bucketeer:overflow"; case_insensitive = false; capture_overflow = false; int reti; int case_sensitive = 0; int extended = 0; arg.value(regex); arg.next(); while(!arg.done()) { String arg_value; arg.value(arg_value); const char* val = arg_value.get(); if (strcmp(val,"case-insensitive") == 0) { case_sensitive = REG_ICASE; case_insensitive = true; } else if (strcmp(val,"extended") == 0) { extended = REG_EXTENDED; } else if (strcmp(val,"capture-overflow") == 0) { capture_overflow = true; } arg.next(); } /* Compile regular expression */ reti = regcomp(&amp;regex_compiled, regex.get(), case_sensitive|extended); } ]]&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The first new step to do this was to determine which C++ structure I'd use to collect the information. Obviously a vector wouldn't work for this scenario. I was first drawn to std::map, but quickly discovered it only stored one value per key. That is when I was drawn to std::multimap. So the map function of my UDF basically adds a std::pair&lt;String,String&gt; the multimap with the first being the regex matching portion of the string and second being the full string. Nothing too much more complex than my original go at a UDF.&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="4f70b7a9dabca36dba85" id="gist-4f70b7a9dabca36dba85" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="C++ map MarkLogic UDF function"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="C++"/&gt;&lt;br /&gt;&lt;![CDATA[ void BucketeerRegex:: map(TupleIterator&amp; values, Reporter&amp; reporter) { int reti = 0; for(; !values.done(); values.next()) { if(!values.null(0)) { String cur;  values.value(0,cur); /* Execute regular expression */ regmatch_t pmatch[1]; reti = regexec(&amp;regex_compiled, cur.get(), 1, pmatch, 0); if( !reti ){ // add a place for the trailing NULL int match_length = (pmatch[0].rm_eo - (pmatch[0].rm_so)) + 1; char match_str[match_length]; /* If matches then create a copy of the string */ size_t str_length = strlen(cur.get()); char cp_str[str_length]; strcpy(cp_str,cur.get()); // don't set the last value since it needs to be NULL for (int i = 0; i &lt; (match_length - 1); i++) {           int str_pos = pmatch[0].rm_so + i;           match_str[i] = cp_str[str_pos];         }         // add trailing NULL to match         match_str[match_length - 1] = '\0';         String* match;         // make everything lowercase if case_insensitive option is passed         if (case_insensitive) {           std::string tmp_str = std::string(match_str);           std::transform(tmp_str.begin(), tmp_str.end(),tmp_str.begin(), ::tolower);           match = new String(tmp_str.c_str(),cur.collation());         } else {           match = new String(match_str,cur.collation());         } 		    /* Store the pointer to the marklogic::String for output later */         buckets.insert(std::pair&lt;String, String&gt;(*(match),*(new String(cp_str,cur.collation()))));&lt;br /&gt;} else if (capture_overflow) {&lt;br /&gt;size_t str_length = strlen(cur.get());&lt;br /&gt;char cp_str[str_length];&lt;br /&gt;strcpy(cp_str,cur.get());&lt;br /&gt;buckets.insert(std::pair&lt;String, String&gt;(*(new String(overflow_bucket.c_str(),cur.collation())),*(new String(cp_str,cur.collation()))));&lt;br /&gt;} &lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;]]&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The reduce function actually does the opposite of reduce to result set by inserting each pair from the one multimap into the current multimap.&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="4f70b7a9dabca36dba85" id="gist-4f70b7a9dabca36dba85" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="C++ reduce MarkLogic UDF function"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="C++"/&gt;&lt;br /&gt;&lt;![CDATA[ template&lt;class T&gt;&lt;br /&gt;void Bucketeer&lt;t&gt;::&lt;br /&gt;reduce(const AggregateUDF* _o, Reporter&amp; reporter)&lt;br /&gt;{&lt;br /&gt;/* Merge matches found */&lt;br /&gt;const Bucketeer&lt;t&gt; *o = (const Bucketeer&lt;t&gt;*)_o;&lt;br /&gt;typename std::multimap&lt;String, T&gt; o_buckets = o-&gt;buckets;&lt;br /&gt;for (typename std::multimap&lt;String, T&gt;::iterator it = o_buckets.begin(); it != o_buckets.end(); it++) {&lt;br /&gt;buckets.insert(typename std::pair &lt;String, T&gt; (it-&gt;first, it-&gt;second));&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;]]&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The encode and decode functions are where it actually got a bit more tricky. From the MarkLogic documentation, the functions "encode/decode the implementation-specific state on your objects" and "you can encode data members in any order, but you must be consistent between encode and decode." I might have been able to work some magic with the encode(*void, size_t)/decode(*void, size_t) signatures to just pass the whole multimap in one go, but didn't feel comfortable enough going that route (If any C++ masters have pointers (pun intended) on the matter, feel free to share). Instead I used a pattern that is a flattened representation of the multimap. First the key count is encoded. Then each key is encoded followed by the count of values of that key and its values. This way, as the information is decoded in the decode function, the decode is provided the proper information to decode in the proper order due to the counts and each key/value pair is inserted into the multimap.&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="7484ed5b471cc2e9dda0" id="gist-7484ed5b471cc2e9dda0" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="C++ encode/decode MarkLogic UDF function"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="C++"/&gt;&lt;br /&gt;&lt;![CDATA[ /*  * Encode the map in a flattened state.   */ template&lt;class T&gt;&lt;br /&gt;void Bucketeer&lt;t&gt;::&lt;br /&gt;encode(Encoder&amp; e, Reporter&amp; reporter)&lt;br /&gt;{&lt;br /&gt;std::map&lt;String, int&gt; keys_w_count;&lt;br /&gt;int key_count = 0;&lt;br /&gt;// determine key count and collect unique keys&lt;br /&gt;for (&lt;br /&gt;typename std::multimap&lt;String, T&gt;::iterator it = buckets.begin(); &lt;br /&gt;it != buckets.end(); &lt;br /&gt;// set the iterator to the upperbound of the current key&lt;br /&gt;it = buckets.upper_bound(it-&gt;first)&lt;br /&gt;) {&lt;br /&gt;// store key with count of entries for that key&lt;br /&gt;keys_w_count.insert(std::pair &lt;String, int&gt;(it-&gt;first,buckets.count(it-&gt;first)));&lt;br /&gt;// increment key count&lt;br /&gt;key_count++;&lt;br /&gt;}&lt;br /&gt;// encode key count&lt;br /&gt;e.encode(key_count);&lt;br /&gt;for (std::map&lt;String, int&gt;::iterator it = keys_w_count.begin(); it != keys_w_count.end(); ++it) {&lt;br /&gt;// encode key value&lt;br /&gt;e.encode((it-&gt;first));&lt;br /&gt;// encode count of unique values associated with key&lt;br /&gt;e.encode(it-&gt;second);&lt;br /&gt;std::pair &lt;typename std::multimap&lt;String,T&gt;::iterator, typename std::multimap&lt;String,T&gt;::iterator&gt; ret;&lt;br /&gt;// get iterator for key range&lt;br /&gt;ret = buckets.equal_range(it-&gt;first);&lt;br /&gt;// encode each value for key&lt;br /&gt;for (typename std::multimap&lt;String, T&gt;::iterator it2 = ret.first; it2 != ret.second; ++it2) {&lt;br /&gt;e.encode(it2-&gt;second);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;template&lt;class T&gt;&lt;br /&gt;void Bucketeer&lt;t&gt;::&lt;br /&gt;decode(Decoder&amp; d, Reporter&amp; reporter)&lt;br /&gt;{&lt;br /&gt;int key_count;&lt;br /&gt;// decode key count&lt;br /&gt;d.decode(key_count);&lt;br /&gt;for (int i = 0; i &lt; key_count;i++) {     String key;     int key_size;     // decode key     d.decode(key);     // decode count of key values     d.decode(key_size);     for (int j = 0; j &lt; key_size; j++) {       T value;       // decode value for key       d.decode(value);       // insert key/value pair into our multimap       buckets.insert(typename std::pair &lt;String, T&gt; (key, value));&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;]]&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The finish function then starts a MarkLogic map object and then iterates over the unique keys, first writing the key and then writing each of the values of that key. &lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="cce1d7cc87c860336657" id="gist-cce1d7cc87c860336657" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="C++ finish MarkLogic UDF function"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="C++"/&gt;&lt;br /&gt;&lt;![CDATA[ template&lt;class T&gt;&lt;br /&gt;void Bucketeer&lt;t&gt;::&lt;br /&gt;finish(OutputSequence&amp; os, Reporter&amp; reporter)&lt;br /&gt;{&lt;br /&gt;// start the MarkLogic map&lt;br /&gt;os.startMap();&lt;br /&gt;// interate over the unique keys&lt;br /&gt;// note the use of buckets.upper_bound() to ensure we get a key only once&lt;br /&gt;for (typename std::multimap&lt;String, T&gt;::iterator it = buckets.begin(); it != buckets.end(); it = buckets.upper_bound(it-&gt;first)) {&lt;br /&gt;std::pair &lt;typename std::multimap&lt;String,T&gt;::iterator, typename std::multimap&lt;String,T&gt;::iterator&gt; ret;&lt;br /&gt;// get the range for the key values&lt;br /&gt;ret = buckets.equal_range(it-&gt;first);&lt;br /&gt;// write the map key&lt;br /&gt;os.writeMapKey(it-&gt;first);&lt;br /&gt;// iterate over the values for current key&lt;br /&gt;for (typename std::multimap&lt;String, T&gt;::iterator it2 = ret.first; it2 != ret.second; ++it2) {&lt;br /&gt;// write the value&lt;br /&gt;os.writeValue(it2-&gt;second);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;os.endMap();&lt;br /&gt;}]]&gt;&lt;/div&gt;&lt;br /&gt;What was really cool was after doing this I thought I would like to do a similar thing with dateTime. For example group by year or year and month, etc. Thanks to &lt;a href="http://www.codeproject.com/Articles/257589/An-Idiots-Guide-to-Cplusplus-Templates-Part"&gt;C++ templates&lt;/a&gt; I was able to write an abstract class that implements the reduce, encode, decode, and finish functions. I then extend Bucketeer&lt;datetime&gt; and most of the work from the regex implementation carries over. Really the most difficult part was extracting the year, month, etc. from the dateTime. The only reason that was so difficult was because it took me a while to determine the value of marklogic::DateTime wasn't a Unix timestamp, but actually FILETIME. Once I figured that out I was able to find &lt;a href="http://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/"&gt;this handy information.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So this UDF allows you to bucket by dateTime attributes like year, month, etc. with "dateTime" or regular expression with "regex". You can see the final code here: &lt;a href="https://github.com/ryanjdew/ml-bucketeer"&gt;https://github.com/ryanjdew/ml-bucketeer&lt;/a&gt;.&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/2YamKQyaW7Y" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/2285945151343226641/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2014/05/revisiting-marklogic-aggregate-user.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/2285945151343226641" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/2285945151343226641" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/2YamKQyaW7Y/revisiting-marklogic-aggregate-user.html" title="Revisiting MarkLogic Aggregate User Defined Functions" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2014/05/revisiting-marklogic-aggregate-user.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-715404294783132188</id><published>2013-10-31T08:20:00.000-06:00</published><updated>2014-05-25T07:22:25.556-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic 7" /><category scheme="http://www.blogger.com/atom/ns#" term="memory" /><title type="text">XML Memory Operations 1.0.x Release</title><content type="html">Version 1.0.3 of the XML memory update library is now available on GitHub from the master branch at &lt;a href="https://github.com/ryanjdew/XQuery-XML-Memory-Operations"&gt;https://github.com/ryanjdew/XQuery-XML-Memory-Operations&lt;/a&gt;. It currently requires MarkLogic 6. With this release there are a lot of stability enhancements as well as adjustments to some perhaps excessive strong typing (I do plan in the future to patch the v0.4.x branch, which is compatible with ML 4+, with some of the more stabilizing enhancements). &lt;br /&gt;&lt;br /&gt;Previously, it was required that when using the mem:copy to begin a transaction and then queueing up operations to be done on nodes for that transaction required there be 1 or more nodes to change. The library now allows zero or more nodes and gracefully handles that situation. Further more, previously it would break if you ever just did a copy on invalid XML. This is also handled more gracefully now and will provide you the expected results (although, I still feel that if XML is namespaced and you have a schema, you should probably follow the schema). &lt;br /&gt;&lt;br /&gt;With this 1.0 release, the library was also re-released under the Apache 2.0 License. This was done since the Apache 2.0 License seems to be more friendly with patents, etc. &lt;br /&gt;&lt;br /&gt;Finally, in preparation for MarkLogic 7, I added a second library that you could import instead of the regular one that will allow you to perform operations in a more 'functionally pure' way (read no side-effects). With a change like that, this means that this library could fairly easily be ported to other XQuery implementations that implement Michael Kay's proposal of maps as outlined &lt;a href="http://docs.basex.org/wiki/Map_Module"&gt;here&lt;/a&gt; which will be implemented in MarkLogic 7. While I haven't seen any significant performance differences between the two approaches, it is further validation that most problems can be solved in a functional way. Pretty cool.&lt;br /&gt;&lt;br /&gt;Below are examples contrasting the two approaches.&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="7250295" id="gist-7250295" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Functional way of using memory operations library"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0-ml";&lt;br /&gt;import module namespace mem = "http://maxdewpoint.blogspot.com/memory-operations" at "/memory-operations.xqy";&lt;br /&gt;import module namespace mem-fun = "http://maxdewpoint.blogspot.com/memory-operations/functional" at "/memory-operations-functional.xqy";&lt;br /&gt;&lt;br /&gt;declare variable $test-xml := &lt;html&gt;&lt;br /&gt;&lt;head&gt;&lt;br /&gt;&lt;title&gt;This is a title&lt;/title&gt;&lt;br /&gt;&lt;/head&gt;&lt;br /&gt;&lt;!-- old comment --&gt;&lt;br /&gt;&lt;body&gt;&lt;br /&gt;&lt;div id="div1"&gt;&lt;p class="p1"&gt;&lt;!-- old comment --&gt;This is a paragraph.&lt;/p&gt;&lt;p class="p2"&gt;This is a paragraph.&lt;/p&gt;&lt;p class="p3"&gt;This is a paragraph.&lt;/p&gt;&lt;p class="p4"&gt;This is a paragraph.&lt;/p&gt;&lt;p class="p5"&gt;This is a paragraph.&lt;/p&gt;&lt;/div&gt;&lt;div id="div2"&gt;&lt;p class="p1"&gt;This is a paragraph.&lt;/p&gt;&lt;p class="p2"&gt;This is a paragraph.&lt;/p&gt;&lt;p class="p3"&gt;This is a paragraph.&lt;!-- old comment --&gt;&lt;/p&gt;&lt;p class="p4"&gt;This is a paragraph.&lt;/p&gt;&lt;p class="p5"&gt;This is a paragraph.&lt;/p&gt;&lt;/div&gt;&lt;/body&gt;&lt;br /&gt;&lt;/html&gt;;&lt;br /&gt;&lt;br /&gt;(: stateful way :)&lt;br /&gt;let $new-xml := &lt;br /&gt;let $transaction-id := mem:copy($test-xml) &lt;br /&gt;let $_ :=  (&lt;br /&gt;mem:replace($transaction-id,$test-xml/head/title,element title {"This is so awesome!"}),&lt;br /&gt;mem:insert-child($transaction-id,$test-xml/body/div/p,attribute data-info {"This is also awesome!"})&lt;br /&gt;)&lt;br /&gt;return mem:execute($transaction-id) &lt;br /&gt;&lt;br /&gt;(: functional way :)&lt;br /&gt;&lt;br /&gt;let $functional-new-xml := &lt;br /&gt;mem-fun:execute(&lt;br /&gt;mem-fun:insert-child(&lt;br /&gt;mem-fun:replace(&lt;br /&gt;mem-fun:copy($test-xml),&lt;br /&gt;$test-xml/head/title,&lt;br /&gt;element title {"This is so awesome!"}&lt;br /&gt;),&lt;br /&gt;$test-xml/body/div/p,&lt;br /&gt;attribute data-info {"This is also awesome!"}&lt;br /&gt;)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;return ($new-xml, $functional-new-xml)&lt;/div&gt;&lt;br /&gt;It is my hope that this library will gain wider adoption between the changes enhancing usability, stabilization, and patent friendly license. Let me know if you have any comments or suggestions.&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/T_XVO7epZpo" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/715404294783132188/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2013/10/xml-memory-operations-10x-release.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/715404294783132188" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/715404294783132188" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/T_XVO7epZpo/xml-memory-operations-10x-release.html" title="XML Memory Operations 1.0.x Release" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2013/10/xml-memory-operations-10x-release.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-1561005067524398146</id><published>2013-08-07T18:45:00.000-06:00</published><updated>2013-08-07T18:45:18.574-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="government" /><category scheme="http://www.blogger.com/atom/ns#" term="reform" /><category scheme="http://www.blogger.com/atom/ns#" term="technology" /><title type="text">The Expiring Constitution: How Technology is Up-ending a Government</title><content type="html">&lt;p dir="ltr"&gt;The title to this article may be troubling to some. Some may even dismiss it as unpatriotic and anti-American. That would be unfortunate as this is in no way meant to discount the achievement of the Founding Fathers in bringing about the U.S. Constitution. Even if the Founding Fathers could have foreseen the technological advancements we have achieved since their time, accounting for those advancements in the Constitution would have further threatened what already appeared to be a fragile situation.&lt;/p&gt;&lt;p dir="ltr"&gt;So you&amp;#8217;re probably thinking &amp;#8220;What do you mean &amp;#8216;expiring Constitution?&amp;#8217;&amp;#8221; Technology has completely changed the government landscape. For example, I will bring up Federalist Papers No. 10 and No. 51 which are pillars to the founding of the U.S. Constitution. In these papers James Madison makes the argument for a large republic because it brings about enough diversity that there won&amp;#8217;t be a solid majority of citizens to infringe on the rights of a minority citizens. Essentially, Madison relies on the inefficiencies of his time period in communicating and sharing opinions.&lt;/p&gt;&lt;p dir="ltr"&gt;How do we see some of the consequences of the technology on this outdated principal Madison relied so heavily on? Looking back in history, prior to the current era of the Republican and Democratic parties, we see that political parties changed out about every 30-40 years (Interestingly enough, in the bigger picture of things, not too far off of the 20 year cycle in which Jefferson said a revolution is needed.).&lt;/p&gt;&lt;p dir="ltr"&gt;So what changed that has caused the Republicans and Democrats to hold on for so long? Well, within a decade prior to the era of Democrats and Republicans, the first national newspaper was founded. By the time Republicans and Democrats should have been finding themselves shown the door, communication became efficient enough to solidify over-arching opinions over a large population. Madison&amp;#8217;s fear of a majority faction that would go against the interests of minority groups is &lt;u&gt;now&lt;/u&gt; being realized.&lt;/p&gt;&lt;p dir="ltr"&gt;Now let us fast forward to today and take a look at the 4th amendment and reasonable expectation of privacy. If it isn&amp;#8217;t obvious already, my example is going to address the NSA programs (Not the allegations of use of mal-ware and similar tactics. Those are totally different stories.). Many people act like the NSA programs of monitoring activities on the internet is like having the government invade their home. Any technologist familiar with how the internet works will have to admit it is more like being in a high school locker room and noticing someone gawking. Creepy and perhaps disturbing, but you aren&amp;#8217;t exactly doing much to prevent the view.&lt;/p&gt;&lt;p dir="ltr"&gt;Another issue is the technology as a medium for transferring information. At some point there is a &amp;#8216;middle-man&amp;#8217;, whether it is your ISP or your phone provider. The information provided to them to connect you with where you want to go is theirs to keep and can be shared however they really see fit. There is &lt;a href="http://www.newyorker.com/online/blogs/elements/2013/08/why-your-cell-phones-location-isnt-protected-by-the-fourth-amendment.html"&gt;excellent article on this topic&lt;/a&gt; that I&amp;#8217;m sure I&amp;#8217;m giving no justice to.&lt;/p&gt;&lt;p dir="ltr"&gt;So in this case, what is reasonable the expectation of privacy? It depends on how tech-savvy you are and how much you trust your &amp;#8216;middle-man&amp;#8217;. Rightly so, people are concerned that the actions of the NSA may harm the openness of the Internet. Oddly enough it is the openness of the Internet that has allowed the NSA to do what it does and it is attempts to prevent the NSA from having access to our information that will kill the openness of the Internet.&lt;/p&gt;&lt;p dir="ltr"&gt;So what do we do to solve the issue? We need people familiar with technology, such as &lt;a href="http://www.rushkoff.com/"&gt;Douglas &lt;/a&gt;&lt;a href="http://www.rushkoff.com/"&gt;Rushkoff&lt;/a&gt;, to make reasonable laws surrounding our digital privacy. We need technological innovations, such as peer-to-peer networking, that provide ample privacy, but prevents those innovations from becoming nesting grounds for &lt;a href="http://siliconangle.com/blog/2013/08/06/darknet-freedom-hosting-sites-shutdown-led-by-fbi-exploit-use-against-tor-network/"&gt;child abuse&lt;/a&gt; and other horrendous acts. We need to meticulously comb over our laws as to &lt;a href="http://www.heritage.org/research/reports/2013/03/guilty-until-proven-innocent-undermining-the-criminal-intent-requirement"&gt;what we deem criminal&lt;/a&gt; and do some soul searching as to whether those laws make sense. Lastly, but perhaps most important, we need to &lt;a href="http://www.rootstrikers.org/"&gt;change our elections&lt;/a&gt; so that we can have a government that the American people can trust again.&lt;/p&gt;&lt;p dir="ltr"&gt;I'm sure there are many opinions on this and you're more than welcome to comment. Please be civil, though. I am moderating any comments that are made.&lt;br /&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/p9Tspd0Hjm4" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/1561005067524398146/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2013/08/the-expiring-constitution-how.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/1561005067524398146" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/1561005067524398146" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/p9Tspd0Hjm4/the-expiring-constitution-how.html" title="The Expiring Constitution: How Technology is Up-ending a Government" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2013/08/the-expiring-constitution-how.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-573186153152023823</id><published>2013-05-25T21:28:00.000-06:00</published><updated>2014-05-25T07:22:47.794-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Coding by Superstition" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic" /><category scheme="http://www.blogger.com/atom/ns#" term="security" /><category scheme="http://www.blogger.com/atom/ns#" term="xQuery" /><category scheme="http://www.blogger.com/atom/ns#" term="XQuery hardening" /><category scheme="http://www.blogger.com/atom/ns#" term="XQuery injection" /><title type="text">Coding by Superstition: XQuery Sanitization</title><content type="html">&lt;meta itemprop="name" content="Coding by Superstition: XQuery Sanitization"/&gt;&lt;br /&gt;There is a great talk given at The Markup Conference 2011 that covers the potential dangers of XQuery injection. The emphasis of that talk was to use sanitization as a method for preventing XQuery injection. In the example given, REST APIs were used to execute queries and the REST APIs were created in such a way that the end client could pass the exact query to be executed.&lt;sup&gt;&lt;a href="#footnote-1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;&lt;br /&gt;While there is no argument that such an approach can be effective, I would argue with the question of "Why would such an exploitable API even exist?" The power of dynamically generated XML can be leveraged, while maintaining a hardened system that isn't open to XQuery injection. I will show how this can be done with two examples of dynamically built order by clauses. The first could be potentially be exploited with XQuery injection, while the second has been hardened to prevent such an attack.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="5636218" id="gist-5636218" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="XQuery that can be subject to XQuery injection"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0-ml";&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;declare function local:prolog($element as element()) {&lt;br /&gt;if ($element instance of element(value))&lt;br /&gt;then&lt;br /&gt;fn:string-join(&lt;br /&gt;local:prolog-ns($element/*),&lt;br /&gt;"&amp;#10;"&lt;br /&gt;)&lt;br /&gt;else ()&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:prolog-ns($element as element()) {&lt;br /&gt;let $qname := fn:resolve-QName(fn:string($element),$element)&lt;br /&gt;let $prefix := fn:prefix-from-QName($qname)&lt;br /&gt;where $prefix&lt;br /&gt;return &lt;br /&gt;fn:concat("declare namespace ", $prefix, " = '", fn:namespace-uri-from-QName($qname), "';")&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:order-by($element as element()) {&lt;br /&gt;typeswitch($element)&lt;br /&gt;case element(score) return "cts:score($r) descending"&lt;br /&gt;default return&lt;br /&gt;fn:concat(&lt;br /&gt;"$r/descendant-or-self::",&lt;br /&gt;fn:string($element/element),"[1]",&lt;br /&gt;if ($element[attribute])&lt;br /&gt;then fn:concat("/@",$element/attribute/fn:string())&lt;br /&gt;else (),&lt;br /&gt;" ",&lt;br /&gt;if ($element/@direction eq "descending")&lt;br /&gt;then "descending"&lt;br /&gt;else "ascending"&lt;br /&gt;)&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;let $options := &amp;lt;options&amp;gt;&lt;br /&gt;&amp;lt;sort&amp;gt;&lt;br /&gt;&amp;lt;score/&amp;gt;&lt;br /&gt;&amp;lt;value xmlns:test="http://maxdewpoint.blogspot.com/test-fn-data"&amp;gt;&lt;br /&gt;&amp;lt;element&amp;gt;test:id&amp;lt;/element&amp;gt;&lt;br /&gt;&amp;lt;/value&amp;gt;&lt;br /&gt;&amp;lt;value xmlns:html="http://www.w3.org/1999/xhtml"&amp;gt;&lt;br /&gt;&amp;lt;element&amp;gt;html:div&amp;lt;/element&amp;gt;&lt;br /&gt;&amp;lt;attribute&amp;gt;id&amp;lt;/attribute&amp;gt;&lt;br /&gt;&amp;lt;/value&amp;gt;&lt;br /&gt;&amp;lt;/sort&amp;gt;&lt;br /&gt;&amp;lt;/options&amp;gt;&lt;br /&gt;return&lt;br /&gt;xdmp:eval(&lt;br /&gt;fn:concat(&lt;br /&gt;"xquery version '1.0-ml';&lt;br /&gt;",&lt;br /&gt;fn:string-join(&lt;br /&gt;local:prolog($options/sort/*),&lt;br /&gt;"&amp;#10;"&lt;br /&gt;)&lt;br /&gt;,"&lt;br /&gt;&lt;br /&gt;for $r in cts:search(fn:collection(), cts:and-query(()))[1 to 50]&lt;br /&gt;", if ($options/sort[*])&lt;br /&gt;then fn:concat("order by ", fn:string-join(local:order-by($options/sort/*),", "), "&amp;#10;")&lt;br /&gt;else (),&lt;br /&gt;"return $r"&lt;br /&gt;)&lt;br /&gt;)&lt;/div&gt;&lt;br /&gt;You will notice that in the code above values are taken directly from values in the options XML that we pass in order to generate the order by clause in our XQuery. Those are potential areas that could be subject to XQuery injection.&lt;br /&gt;&lt;br /&gt;Below we have code that doesn't use any of the values directly in generating our XQuery, but it makes use of the XML options to determine how to create external variables which then are used in our order by clause. This method of XQuery hardening prevents XQuery injection and affords you the ease of not having to track which inputs need sanitized. Further, you don't have the worry about the trade off of sanitization and potentially affecting the quality of the application's inputs.&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="5636226" id="gist-5636226" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="XQuery that has been hardened against XQuery injection"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0-ml";&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;declare function local:prolog($element as element(), $position as xs:integer) {&lt;br /&gt;if ($element instance of element(value))&lt;br /&gt;then&lt;br /&gt;fn:string-join(&lt;br /&gt;local:prolog-var($element/*, $position),&lt;br /&gt;"&amp;#10;"&lt;br /&gt;)&lt;br /&gt;else ()&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:prolog-var($element as element(), $position as xs:integer) {&lt;br /&gt;fn:concat(&lt;br /&gt;"declare variable ",&lt;br /&gt;local:var-name($element, $position),&lt;br /&gt;" external;")&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:var-name($element as element(), $position as xs:integer) {&lt;br /&gt;fn:concat(&lt;br /&gt;"$",&lt;br /&gt;if ($element instance of element(element))&lt;br /&gt;then "element"&lt;br /&gt;else "attribute",&lt;br /&gt;"-qn-",&lt;br /&gt;fn:string($position))&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:order-by($element as element(), $position as xs:integer) {&lt;br /&gt;typeswitch($element)&lt;br /&gt;case element(score) return "cts:score($r) descending"&lt;br /&gt;default return&lt;br /&gt;fn:concat(&lt;br /&gt;"$r/descendant-or-self::*[fn:node-name(.) eq ",&lt;br /&gt;local:var-name($element/element, $position),&lt;br /&gt;"][1]",&lt;br /&gt;if ($element[attribute])&lt;br /&gt;then fn:concat("/@*[fn:node-name(.) eq ",$element/attribute/local:var-name(., $position), ']')&lt;br /&gt;else (),&lt;br /&gt;" ",&lt;br /&gt;if ($element/@direction eq "descending")&lt;br /&gt;then "descending"&lt;br /&gt;else "ascending"&lt;br /&gt;)&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;let $options := &amp;lt;options&amp;gt;&lt;br /&gt;&amp;lt;sort&amp;gt;&lt;br /&gt;&amp;lt;score/&amp;gt;&lt;br /&gt;&amp;lt;value xmlns:test="http://maxdewpoint.blogspot.com/test-fn-data"&amp;gt;&lt;br /&gt;&amp;lt;element&amp;gt;test:id&amp;lt;/element&amp;gt;&lt;br /&gt;&amp;lt;/value&amp;gt;&lt;br /&gt;&amp;lt;value xmlns:html="http://www.w3.org/1999/xhtml"&amp;gt;&lt;br /&gt;&amp;lt;element&amp;gt;html:div&amp;lt;/element&amp;gt;&lt;br /&gt;&amp;lt;attribute&amp;gt;id&amp;lt;/attribute&amp;gt;&lt;br /&gt;&amp;lt;/value&amp;gt;&lt;br /&gt;&amp;lt;/sort&amp;gt;&lt;br /&gt;&amp;lt;/options&amp;gt;&lt;br /&gt;return&lt;br /&gt;xdmp:eval(&lt;br /&gt;fn:concat(&lt;br /&gt;"xquery version '1.0-ml';&lt;br /&gt;",&lt;br /&gt;fn:string-join(&lt;br /&gt;for $e at $pos in $options/sort/*&lt;br /&gt;return local:prolog($e,$pos),&lt;br /&gt;"&amp;#10;"&lt;br /&gt;)&lt;br /&gt;,"&lt;br /&gt;&lt;br /&gt;for $r in cts:search(fn:collection(), cts:and-query(()))[1 to 50]&lt;br /&gt;", if ($options/sort[*])&lt;br /&gt;then &lt;br /&gt;fn:concat("order by ", &lt;br /&gt;fn:string-join(&lt;br /&gt;for $e at $pos in $options/sort/*&lt;br /&gt;return local:order-by($e, $pos),", "), "&amp;#10;")&lt;br /&gt;else (),&lt;br /&gt;"return $r"&lt;br /&gt;), &lt;br /&gt;(&lt;br /&gt;for $e at $pos in $options/sort/*&lt;br /&gt;return &lt;br /&gt;if ($e instance of element(value))&lt;br /&gt;then &lt;br /&gt;for $e in $e/* &lt;br /&gt;return (xs:QName(fn:replace(local:var-name($e,$pos), "^\$","")),fn:resolve-QName(fn:string($e),$e))&lt;br /&gt;else ()&lt;br /&gt;)&lt;br /&gt;)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;[&lt;a name="footnote-1"&gt;1&lt;/a&gt;] van der Vlist, Eric. “&lt;a href="http://www.balisage.net/Proceedings/vol7/html/Vlist02/BalisageVol7-Vlist02.html"&gt;XQuery Injection: Easy to exploit, easy to prevent....&lt;/a&gt;” Presented at Balisage: The Markup Conference 2011, Montréal, Canada, August 2 - 5, 2011. In Proceedings of Balisage: The Markup Conference 2011. Balisage Series on Markup Technologies, vol. 7 (2011). doi:10.4242/BalisageVol7.Vlist02.&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/7feHOwwaQlo" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/573186153152023823/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2013/05/coding-by-superstition-xquery.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/573186153152023823" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/573186153152023823" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/7feHOwwaQlo/coding-by-superstition-xquery.html" title="Coding by Superstition: XQuery Sanitization" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2013/05/coding-by-superstition-xquery.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-635563949056113161</id><published>2013-05-02T06:55:00.000-06:00</published><updated>2013-05-02T06:55:10.821-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Coding by Superstition" /><category scheme="http://www.blogger.com/atom/ns#" term="encapsulation" /><category scheme="http://www.blogger.com/atom/ns#" term="xQuery" /><title type="text">Coding by Superstition: Encapsulation</title><content type="html">Encapsulation is great tool in software engineering. It makes life easier when a programmer doesn't have to rework out in his mind the details of an operation each time each they revisit a problem. It is far better to just pass values to the black box and get back what you need. This is precisely why MarkLogic provided private modifiers and XQuery 3.0 provided the private annotation (%private).&lt;br /&gt;&lt;br /&gt;Unfortunately, some encapsulation practices from the object-oriented world can sneak into the functional world of XQuery. I'm talking about the dreaded getters and setters. There are few times, if any, that an XQuery program should have setters (In actuality, XQuery without extensions cannot have setters.). Setters can really cause issues by introducing side effects that could cause you to lose out on potential optimizations that could be made (&lt;a href="http://en.wikipedia.org/wiki/Functional_programming#Pure_functions"&gt;http://en.wikipedia.org/wiki/Functional_programming#Pure_functions&lt;/a&gt;). In fact, if I were part MarkLogic Technical Support, I would push MarkLogic to not even mention xdmp:set in any of their documentation. Since ideally we wouldn't have any setters, why would we prefix functions with 'get'?&lt;br /&gt;&lt;br /&gt;Going even further, for simple constant (per transaction) values, why wouldn't we just use global variables since they are immutable? This can make code more clear as to what is going on. Otherwise meaning can easily be lost as a variable is passed around through functions if special care isn't taken. &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/OQdrlQYPfAA" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/635563949056113161/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2013/05/coding-by-superstition-encapsulation.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/635563949056113161" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/635563949056113161" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/OQdrlQYPfAA/coding-by-superstition-encapsulation.html" title="Coding by Superstition: Encapsulation" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2013/05/coding-by-superstition-encapsulation.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-8313783433634405816</id><published>2013-02-23T07:29:00.000-07:00</published><updated>2014-05-25T07:23:22.393-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="boolean" /><category scheme="http://www.blogger.com/atom/ns#" term="Coding by Superstition" /><category scheme="http://www.blogger.com/atom/ns#" term="xQuery" /><title type="text">Coding by Superstition: XQuery Booleans</title><content type="html">The next few posts I make are going to be part of a series I am calling, "Coding by Superstition." This series, which I will probably revisit from time to time, is to address programming practices that I have encountered that seem to indicate a lack of understanding. This first post is about use of booleans in XQuery.&lt;br /&gt;&lt;br /&gt;I've come across some interesting code dealing with booleans in XQuery. Here are a few examples:&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="5004863" id="gist-5004863" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Bad Boolean Examples in XQuery"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;let $items as xs:string* := ('test', 'values', 'to', 'iterate', 'over')&lt;br /&gt;$bool1 as xs:boolean := if ($items) then fn:true() else fn:false(),&lt;br /&gt;$bool2 as xs:boolean? := if (fn:subsequence($items,6)) then fn:true() else (),&lt;br /&gt;$bool3 as xs:boolean* := for $i in $items return $i eq "some-value",&lt;br /&gt;$bool4 as xs:boolean* := for $i in $items return $i eq "iterate"&lt;br /&gt;&lt;br /&gt;return (&lt;br /&gt;if ($bool1)&lt;br /&gt;then "bool1: true"&lt;br /&gt;else (),&lt;br /&gt;if ($bool2)&lt;br /&gt;then "bool2: true"&lt;br /&gt;else (),&lt;br /&gt;if ($bool3)&lt;br /&gt;then "bool3: true"&lt;br /&gt;else (),&lt;br /&gt;if ($bool4)&lt;br /&gt;then "bool4: true"&lt;br /&gt;else ()&lt;br /&gt;)&lt;/div&gt;&lt;br /&gt;I think these interesting examples come out due to a combination of two things; 1.) not understanding the somewhat complex rules behind effective boolean values and 2.) not realizing the effects of function mapping in MarkLogic's XQuery version "1.0-ml". Below are summaries of the effective boolean rules that can be found &lt;a href="http://www.w3.org/TR/xquery/#id-ebv"&gt;here.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Empty sequences are treated as false&lt;/li&gt;&lt;li&gt;If the first item in a sequence is a node it is treated as true&lt;/li&gt;&lt;li&gt;If it is a single boolean value it is treated as that boolean value&lt;/li&gt;&lt;li&gt;If it is a single string, then if it is zero length it is treated as false; otherwise it is treated as true&lt;/li&gt;&lt;li&gt;If it is a single numeric value, then if the value is NaN or zero it is treated as false; otherwise it is treated as true&lt;/li&gt;&lt;li&gt;All other scenarios throw an error&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Now throw in function mapping from MarkLogic, and you almost never encounter the last scenario. It that case, if any of the items in a sequence's effective boolean value results in true then the value used is true. That is why, outside of predicates, I feel it is best to avoid effective boolean values and be explicit in what your condition is. Below are some better boolean examples.&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="5019940" id="gist-5019940" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Good Boolean Examples in XQuery"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;let $items as xs:string* := ('test', 'values', 'to', 'iterate', 'over')&lt;br /&gt;$bool1 as xs:boolean := fn:exists($items[. ne '']),&lt;br /&gt;$bool2 as xs:boolean := fn:exists(fn:subsequence($items,6)),&lt;br /&gt;$bool3 as xs:boolean := some $i in $items satisfies $i eq "some-value",&lt;br /&gt;$bool4 as xs:boolean := every $i in $items satisfies $i instance of xs:string&lt;br /&gt;&lt;br /&gt;return (&lt;br /&gt;if ($bool1)&lt;br /&gt;then "bool1: true"&lt;br /&gt;else (),&lt;br /&gt;if ($bool2)&lt;br /&gt;then "bool2: true"&lt;br /&gt;else (),&lt;br /&gt;if ($bool3)&lt;br /&gt;then "bool3: true"&lt;br /&gt;else (),&lt;br /&gt;if ($bool4)&lt;br /&gt;then "bool4: true"&lt;br /&gt;else ()&lt;br /&gt;)&lt;/div&gt;&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/nXEEKX-8kDM" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/8313783433634405816/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2013/02/coding-by-superstition-xquery-booleans.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/8313783433634405816" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/8313783433634405816" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/nXEEKX-8kDM/coding-by-superstition-xquery-booleans.html" title="Coding by Superstition: XQuery Booleans" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2013/02/coding-by-superstition-xquery-booleans.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-2175190355536897925</id><published>2013-02-16T19:01:00.001-07:00</published><updated>2014-05-25T07:24:01.596-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="transform XML" /><category scheme="http://www.blogger.com/atom/ns#" term="XML" /><category scheme="http://www.blogger.com/atom/ns#" term="xQuery" /><title type="text">A New Way to Transform XML</title><content type="html">In the MarkLogic Application Developer's guide there is a example of a &lt;a href="http://docs.marklogic.com/guide/app-dev/typeswitch#id_28577"&gt;recursive typeswitch transform.&lt;/a&gt; This is very efficient to use, but might not be as flexible as you would like. For example, you might want a central place to make transformation calls, but allow the user calling have more power over the transformation. &lt;br /&gt;&lt;br /&gt;One solution to this is the Translator design pattern found &lt;a href="http://www.balisage.net/Proceedings/vol5/html/Candillon01/BalisageVol5-Candillon01.html"&gt;here.&lt;/a&gt; By passing function references, the user can have more control. &lt;br /&gt;&lt;br /&gt;Below is an approach that I came up with that is kind of a hybrid between the 2 previous design patterns. It uses functions associated with xs:QNames. The QNames are used to find elements to transform with the associated function. Below I converted the example given in the Application Developer's Guide to use my new method. Note that you will want to take into consideration performance when looking at this new method. The performance difference will also change depending on just how much of the XML is being changed with the transform. &lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="4968426" id="gist-4968426" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="A New Way to Transform XML in ML 6"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0-ml";&lt;br /&gt;import module namespace mem = "http://maxdewpoint.blogspot.com/memory-operations" at "/memory-operations.xqy";&lt;br /&gt;(: Functions for transforming xml :)&lt;br /&gt;declare function local:bar($node as node()) as node()*&lt;br /&gt;{&lt;br /&gt;&lt;barr&gt;{$node/node()}&lt;/barr&gt;&lt;br /&gt;};&lt;br /&gt;declare function local:baz($node as node()) as node()*&lt;br /&gt;{&lt;br /&gt;&lt;bazz&gt;{$node/node()}&lt;/bazz&gt;&lt;br /&gt;};&lt;br /&gt;declare function local:buzz($node as node()) as node()*&lt;br /&gt;{&lt;br /&gt;&lt;buzzz&gt;{$node/node()}&lt;/buzzz&gt;&lt;br /&gt;};&lt;br /&gt;declare function local:foo($node as node()) as node()*&lt;br /&gt;{&lt;br /&gt;&lt;fooo&gt;{$node/node()}&lt;/fooo&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;(: This functions returns QNames of elements to change followed by the function that makes the change :)&lt;br /&gt;declare function local:instructions() as item()*&lt;br /&gt;{&lt;br /&gt;xs:QName('bar'),local:bar#1,xs:QName('baz'),local:baz#1,xs:QName('buzz'),local:buzz#1,xs:QName('foo'),local:foo#1&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:process($node as node()) as node()*&lt;br /&gt;{&lt;br /&gt;local:process($node,local:instructions#0)&lt;br /&gt;};&lt;br /&gt;(: process node :)&lt;br /&gt;declare function local:process($node as node(),$instruction-funs as function() as item()*+) as node()*&lt;br /&gt;{&lt;br /&gt;let $transaction-id := mem:copy($node),&lt;br /&gt;$instructions := $instruction-funs ! .()&lt;br /&gt;return (&lt;br /&gt;fn:map-pairs(&lt;br /&gt;function($qname,$fun){&lt;br /&gt;let $nodes-to-mod := $node/descendant-or-self::*[fn:node-name(.) eq $qname]&lt;br /&gt;where fn:exists($nodes-to-mod)&lt;br /&gt;return mem:transform($transaction-id,$nodes-to-mod, $fun)&lt;br /&gt;},&lt;br /&gt;$instructions[. instance of xs:QName],&lt;br /&gt;$instructions[. instance of function(*)]&lt;br /&gt;),&lt;br /&gt;mem:execute($transaction-id)&lt;br /&gt;)&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;let $x := &lt;br /&gt;&lt;foo&gt;foo&lt;br /&gt;&lt;bar&gt;bar&lt;/bar&gt;&lt;br /&gt;&lt;baz&gt;baz&lt;br /&gt;&lt;buzz&gt;buzz&lt;/buzz&gt;&lt;br /&gt;&lt;/baz&gt;&lt;br /&gt;foo&lt;br /&gt;&lt;/foo&gt;&lt;br /&gt;return&lt;br /&gt;local:process($x)&lt;/div&gt;&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/Nf2s39riIKo" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/2175190355536897925/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2013/02/a-new-way-to-transform-xml.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/2175190355536897925" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/2175190355536897925" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/Nf2s39riIKo/a-new-way-to-transform-xml.html" title="A New Way to Transform XML" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>1</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2013/02/a-new-way-to-transform-xml.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-3937167235901273786</id><published>2013-02-15T07:06:00.000-07:00</published><updated>2014-05-25T07:24:23.347-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic 6" /><category scheme="http://www.blogger.com/atom/ns#" term="sliding window" /><category scheme="http://www.blogger.com/atom/ns#" term="XQuery 3.0" /><title type="text">Revisiting The Sliding Window in MarkLogic 6</title><content type="html">Like my &lt;a href="http://maxdewpoint.blogspot.com/2013/02/revisiting-tumbling-window-in-ml-6.html"&gt;previous post&lt;/a&gt; this code revisits my &lt;a href="http://maxdewpoint.blogspot.com/2012/03/xquery-30-sliding-window.html"&gt;implementation of a sliding window.&lt;/a&gt; For more information on sliding windows go &lt;a href="http://www.w3.org/TR/xquery-30/#id-sliding-windows"&gt;here.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="4960516" id="gist-4960516" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="XQuery in ML 6 for a sliding window"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0-ml";&lt;br /&gt;&lt;br /&gt;declare function local:sliding-window(&lt;br /&gt;$sequence as item()*,&lt;br /&gt;$only-start as xs:boolean,&lt;br /&gt;$start-condition as function(*),&lt;br /&gt;$only-end as xs:boolean,&lt;br /&gt;$end-condition as function(*),&lt;br /&gt;$return as function(*)&lt;br /&gt;) {&lt;br /&gt;let $windows as map:map := map:map(),&lt;br /&gt;$sequence-size as xs:unsignedInt := fn:count($sequence) &lt;br /&gt;for $item at $pos in $sequence&lt;br /&gt;let $start as xs:boolean := &lt;br /&gt;((fn:not($only-start) and 1 eq $pos) or&lt;br /&gt;(switch (fn:function-arity($start-condition)) &lt;br /&gt;case 2 return $start-condition($item,$pos)&lt;br /&gt;default return $start-condition($item))&lt;br /&gt;),&lt;br /&gt;$_ as empty-sequence() := &lt;br /&gt;if ($start) &lt;br /&gt;then &lt;br /&gt;let $window-map := map:map()&lt;br /&gt;return (&lt;br /&gt;map:put($window-map,'start',$item),&lt;br /&gt;map:put($window-map,'start-pos',$pos),&lt;br /&gt;map:put($windows,local:_next-key($windows),$window-map)&lt;br /&gt;) else ()&lt;br /&gt;for $window-key in map:keys($windows)&lt;br /&gt;let $window-map as map:map := map:get($windows,$window-key),&lt;br /&gt;$end as xs:boolean :=    &lt;br /&gt;((fn:not($only-end) and $sequence-size eq $pos) or&lt;br /&gt;(switch (fn:function-arity($end-condition)) &lt;br /&gt;case 4 return $end-condition($item,$pos,map:get($window-map,'start'),map:get($window-map,'start-pos'))&lt;br /&gt;case 3 return $end-condition($item,$pos,map:get($window-map,'start'))&lt;br /&gt;case 2 return $end-condition($item,$pos)&lt;br /&gt;default return $end-condition($item))&lt;br /&gt;),&lt;br /&gt;$_ as empty-sequence() := map:put($window-map,'window',(map:get($window-map,'window'),$item))&lt;br /&gt;where $end&lt;br /&gt;return &lt;br /&gt;(&lt;br /&gt;switch (fn:function-arity($return))&lt;br /&gt;case 5 return $return(map:get($window-map,'window'),map:get($window-map,'start'),map:get($window-map,'start-pos'),$item, $pos)&lt;br /&gt;case 4 return $return(map:get($window-map,'window'),map:get($window-map,'start'),map:get($window-map,'start-pos'),$item)&lt;br /&gt;case 3 return $return(map:get($window-map,'window'),map:get($window-map,'start'),map:get($window-map,'start-pos'))&lt;br /&gt;case 2 return $return(map:get($window-map,'window'),map:get($window-map,'start'))&lt;br /&gt;default return $return(map:get($window-map,'window')),&lt;br /&gt;map:delete($windows,$window-key)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:_next-key($windows as map:map) as xs:string {&lt;br /&gt;fn:string((fn:max(map:keys($windows) ! xs:unsignedInt(.)), 0)[1] + 1)&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;local:sliding-window(&lt;br /&gt;(: sequence :)&lt;br /&gt;(2, 4, 6, 8, 10, 12, 14),&lt;br /&gt;(: only start? :)&lt;br /&gt;fn:false(),&lt;br /&gt;(: lambda for start condition :)&lt;br /&gt;function($start) {fn:true()},&lt;br /&gt;(: only end? :)&lt;br /&gt;fn:true(),&lt;br /&gt;(: lambda for end condition :)&lt;br /&gt;function($end, $end-pos, $start, $start-pos) { $end-pos - $start-pos eq 2 },&lt;br /&gt;(: lambda for returning window :)&lt;br /&gt;function($window as item()*, $first as item(), $first-pos as xs:unsignedInt, $last as item()) {&amp;lt;window&amp;gt;{ $first,$last }&amp;lt;/window&amp;gt;}&lt;br /&gt;)&lt;/div&gt;&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/2iNTADLfB4Q" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/3937167235901273786/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2013/02/revisiting-sliding-window-in-marklogic-6.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/3937167235901273786" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/3937167235901273786" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/2iNTADLfB4Q/revisiting-sliding-window-in-marklogic-6.html" title="Revisiting The Sliding Window in MarkLogic 6" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2013/02/revisiting-sliding-window-in-marklogic-6.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-7524253990427590801</id><published>2013-02-15T06:56:00.001-07:00</published><updated>2014-05-25T07:25:13.459-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic 6" /><category scheme="http://www.blogger.com/atom/ns#" term="tumbling window" /><category scheme="http://www.blogger.com/atom/ns#" term="XQuery 3.0" /><title type="text">Revisiting The Tumbling Window in ML 6</title><content type="html">I was thinking about my previous post I made on &lt;a href="http://maxdewpoint.blogspot.com/2012/03/xquery-30-tumbling-window.html"&gt;tumbling windows in XQuery 1.0&lt;/a&gt;. Now with MarkLogic 6 the task has become much more simple and reusable. In the example below I use inline functions for the start/end conditions and for the returned output. For more information on tumbling windows go &lt;a href="http://www.w3.org/TR/xquery-30/#id-tumbling-windows"&gt;here.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="4957340" id="gist-4957340" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="XQuery in ML 6 for a tumbling windows"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0-ml";&lt;br /&gt;&lt;br /&gt;declare function local:tumbling-window(&lt;br /&gt;$sequence as item()*,&lt;br /&gt;$only-start as xs:boolean,&lt;br /&gt;$start-condition as function(*),&lt;br /&gt;$only-end as xs:boolean,&lt;br /&gt;$end-condition as function(*),&lt;br /&gt;$return as function(*)&lt;br /&gt;) {&lt;br /&gt;let $map as map:map := map:map(),&lt;br /&gt;$sequence-size as xs:unsignedInt := fn:count($sequence) &lt;br /&gt;for $item at $pos in $sequence&lt;br /&gt;let $start as xs:boolean := &lt;br /&gt;((fn:not($only-start) and 1 eq $pos) or&lt;br /&gt;(switch (fn:function-arity($start-condition)) &lt;br /&gt;case 2 return $start-condition($item,$pos)&lt;br /&gt;default return $start-condition($item))&lt;br /&gt;),&lt;br /&gt;$started as xs:boolean := map:count($map) gt 0,&lt;br /&gt;$_ as empty-sequence() := if ($start and fn:not($started)) then (map:put($map,'start',$item),map:put($map,'start-pos',$pos)) else (),&lt;br /&gt;$end as xs:boolean :=&lt;br /&gt;((fn:not($only-end) and $sequence-size eq $pos) or&lt;br /&gt;(switch (fn:function-arity($end-condition)) &lt;br /&gt;case 4 return $end-condition($item,$pos,map:get($map,'start'),map:get($map,'start-pos'))&lt;br /&gt;case 3 return $end-condition($item,$pos,map:get($map,'start'))&lt;br /&gt;case 2 return $end-condition($item,$pos)&lt;br /&gt;default return $end-condition($item))&lt;br /&gt;),&lt;br /&gt;$window-started as xs:boolean := $start or $started,&lt;br /&gt;$_ as empty-sequence() := if ($window-started) then map:put($map,'window',(map:get($map,'window'),$item)) else ()&lt;br /&gt;where $end and $window-started&lt;br /&gt;return &lt;br /&gt;(&lt;br /&gt;switch (fn:function-arity($return))&lt;br /&gt;case 5 return $return(map:get($map,'window'),map:get($map,'start'),map:get($map,'start-pos'),$item, $pos)&lt;br /&gt;case 4 return $return(map:get($map,'window'),map:get($map,'start'),map:get($map,'start-pos'),$item)&lt;br /&gt;case 3 return $return(map:get($map,'window'),map:get($map,'start'),map:get($map,'start-pos'))&lt;br /&gt;case 2 return $return(map:get($map,'window'),map:get($map,'start'))&lt;br /&gt;default return $return(map:get($map,'window')),&lt;br /&gt;map:clear($map)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;local:tumbling-window(&lt;br /&gt;(: sequence :)&lt;br /&gt;(2, 4, 6, 8, 10, 12, 14),&lt;br /&gt;(: only start? :)&lt;br /&gt;fn:false(),&lt;br /&gt;(: lambda for start condition :)&lt;br /&gt;function($start) {fn:true()},&lt;br /&gt;(: only end? :)&lt;br /&gt;fn:true(),&lt;br /&gt;(: lambda for end condition :)&lt;br /&gt;function($end, $end-pos, $start, $start-pos) { $end-pos - $start-pos eq 2 },&lt;br /&gt;(: lambda for returning window :)&lt;br /&gt;function($window as item()*, $first as item(), $first-pos as xs:unsignedInt, $last as item()) {&lt;window&gt;{ $first,$last }&lt;/window&gt;}&lt;br /&gt;)&lt;/div&gt;&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/3wXYtzXZNfo" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/7524253990427590801/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2013/02/revisiting-tumbling-window-in-ml-6.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/7524253990427590801" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/7524253990427590801" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/3wXYtzXZNfo/revisiting-tumbling-window-in-ml-6.html" title="Revisiting The Tumbling Window in ML 6" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2013/02/revisiting-tumbling-window-in-ml-6.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-7017597321044143460</id><published>2013-02-02T14:36:00.000-07:00</published><updated>2014-05-25T07:25:32.840-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="HTML" /><category scheme="http://www.blogger.com/atom/ns#" term="microdata" /><category scheme="http://www.blogger.com/atom/ns#" term="non-ob" /><category scheme="http://www.blogger.com/atom/ns#" term="unobtrusive XQuery" /><category scheme="http://www.blogger.com/atom/ns#" term="XML" /><category scheme="http://www.blogger.com/atom/ns#" term="xQuery" /><category scheme="http://www.blogger.com/atom/ns#" term="XQuery 3.0" /><title type="text">Extreme Unob: Prototype to Production HTML Applications</title><content type="html">I kind of poke fun with the title of this post, but there is a great idea Ryan Semerau calls "Non-obtrusive HTML Replacing (non-ob)". If you haven't haven't read his article on it, I encourage you to do so &lt;a href="http://xquerywebappdev.wordpress.com/non-obtrusive-html-replacing-non-ob/"&gt;here.&lt;/a&gt; This post is about building on those ideas.&lt;br /&gt;&lt;br /&gt;While Ryan's solution successfully removes some duplication of work in the scenario he describes, there remains the somewhat painstaking task of punching out holes for the dynamic data. My proposal to solve this issue is to add a third mixture to the solution that would bind the content from the database to the content in the HTML. Now I could go off and create my own binding, but why not make use of standards?&lt;br /&gt;&lt;br /&gt;If the prototype HTML contains &lt;a href="http://en.wikipedia.org/wiki/Microdata_(HTML)"&gt;microdata&lt;/a&gt; and we also add microdata to the content in the database, then we have the binding that we are looking for. This is great because we already have a standard AND it encourages semantic (read SEO friendly) web pages. Now that won't solve all side cases, but those that understand project management will tell you that the sooner you get to the last troublesome 10% of project work the better. Using this standard, you could potentially drop the HTML in your database and immediately begin work on that last 10% of what is required to build a new page in your application.&lt;br /&gt;&lt;br /&gt;Below I provide some grossly over simplified example code. The code is meant to convey an idea more than anything, seeing as I haven't even tested it and it makes calls to imaginary functions. (Just to point out, the functions in the mem namespace aren't imaginary and can be found &lt;a href="https://github.com/ryanjdew/XQuery-XML-Memory-Operations"&gt;here.&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="4699287" id="gist-4699287" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="One way to write unobtrusive XQuery code for HTML replacement"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;let $html as element(html) := html:html-for-page($page-uri),&lt;br /&gt;$content-for-page := content:page-content($page-uri),&lt;br /&gt;$transaction-id := mem:copy($html),&lt;br /&gt;$binding-lambda := function ($html, $content) { &lt;br /&gt;for $prop in $html/descendant-or-self::*[@itemprop]&lt;br /&gt;let $prop-name := fn:string($prop/@itemprop),&lt;br /&gt;$prop-value := $content/descendant-or-self::*[@itemprop eq $prop-name]/node()&lt;br /&gt;return &lt;br /&gt;if ($prop-name eq 'url')&lt;br /&gt;then mem:replace-value($transaction-id, ($prop/(@href|@src|@data))[1], $prop-value)&lt;br /&gt;else mem:replace($transaction-id, $prop, element {fn:node-name($prop)} {$prop/@*,$prop-value})&lt;br /&gt;},&lt;br /&gt;$_populate-content := &lt;br /&gt;for $distinct-type in fn:distinct-values($content-for-page/@itemtype)&lt;br /&gt;return &lt;br /&gt;fn:map-pairs(&lt;br /&gt;$binding-lambda,&lt;br /&gt;$html//*[@itemtype eq $distinct-type], &lt;br /&gt;$content-for-page[@itemtype eq $distinct-type]&lt;br /&gt;)&lt;br /&gt;return mem:execute($transaction-id)&lt;/div&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/jF4tILTetas" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/7017597321044143460/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2013/02/extreme-unob-prototype-to-production.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/7017597321044143460" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/7017597321044143460" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/jF4tILTetas/extreme-unob-prototype-to-production.html" title="Extreme Unob: Prototype to Production HTML Applications" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>2</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2013/02/extreme-unob-prototype-to-production.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-7397044574408579681</id><published>2013-01-08T17:20:00.000-07:00</published><updated>2014-05-25T07:26:37.089-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic 6" /><category scheme="http://www.blogger.com/atom/ns#" term="upgrade path" /><category scheme="http://www.blogger.com/atom/ns#" term="xdmp:from-json" /><title type="text">Making xdmp:from-json Results Work on ML5 and ML6</title><content type="html">You might have the situation where you're caught in-between MarkLogic versions. One environment has MarkLogic 5 and the other has MarkLogic 6. One of the notable changes in ML6 is how JSON is handled. Particularly, if you are using the xdmp:from-json function, the output you get is different.&lt;br /&gt;&lt;br /&gt;This is great for a better representation of JSON, but can be a pain for you to have to go back and change old code to match up exactly. Further, if your code needs to be backwards compatible, there is work to be done on your part.&lt;br /&gt;&lt;br /&gt;Don't worry though, because I've done the work for you. By passing the output of xdmp:from-json to the following function you will get results matching the pattern of ML 5 whether or not you have moved to ML 6.&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="4489184" id="gist-4489184" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Making xdmp:from-json work the same in ML 5 and ML 6"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0-ml";&lt;br /&gt;&lt;br /&gt;declare namespace json = 'http://marklogic.com/xdmp/json';&lt;br /&gt;&lt;br /&gt;declare function local:normalize-from-json($json as item()) {&lt;br /&gt;if (fn:type-available('json:object')) &lt;br /&gt;then local:_normalize-from-json($json)&lt;br /&gt;else $json&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:_normalize-from-json($json as item()) {&lt;br /&gt;typeswitch(document { $json })&lt;br /&gt;case document-node(element(json:object)) return &lt;br /&gt;let $map := map:map(),&lt;br /&gt;$_ := for $map-key in map:keys($json)&lt;br /&gt;return map:put($map, $map-key, local:_normalize-from-json(map:get($json,$map-key)))&lt;br /&gt;return $map&lt;br /&gt;case document-node(element(json:array)) return&lt;br /&gt;local:normalize-from-json(xdmp:apply(xdmp:function(xs:QName('json:array-values')),$json))&lt;br /&gt;default return&lt;br /&gt;$json&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;(: Without xdmp:apply alternative :)&lt;br /&gt;(:&lt;br /&gt;declare function local:_normalize-from-json($json as item()) {&lt;br /&gt;typeswitch(document { $json })&lt;br /&gt;case document-node(element(json:object)) return &lt;br /&gt;let $map := map:map(),&lt;br /&gt;$_ := for $map-key in map:keys($json)&lt;br /&gt;return map:put($map, $map-key, local:_normalize-from-json(map:get($json,$map-key)))&lt;br /&gt;return $map&lt;br /&gt;case document-node(element(map:map)) return &lt;br /&gt;let $map := map:map(),&lt;br /&gt;$_ := for $map-key in map:keys($json)&lt;br /&gt;return map:put($map, $map-key, local:_normalize-from-json(map:get($json,$map-key)))&lt;br /&gt;return $map&lt;br /&gt;case $doc as document-node(element(json:array)) return&lt;br /&gt;local:normalize-from-json(&lt;br /&gt;for $n in $doc/json:array/* &lt;br /&gt;return &lt;br /&gt;if (fn:exists($n/@xsi:type)) &lt;br /&gt;then fn:data($n) &lt;br /&gt;else if (fn:exists($n/json:object)) &lt;br /&gt;then map:map($n/*) &lt;br /&gt;else $n/*)&lt;br /&gt;default return&lt;br /&gt;$json&lt;br /&gt;};&lt;br /&gt;:)&lt;br /&gt;&lt;br /&gt;let $from-json := xdmp:from-json('[{"some-key": [45683, 231321]}, "this is a string", 123]'),&lt;br /&gt;$from-json-old-format := local:normalize-from-json($from-json)&lt;br /&gt;return $from-json-old-format&lt;/div&gt;&lt;br /&gt;While this helps for the in-between phase and is convenient, know that there are definitely advantages to be had with the new output from xdmp:from-json in ML 6. So be sure to make a note to revisit any code you are using this patch for.&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/Kl04Bwn_t18" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/7397044574408579681/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2013/01/making-xdmpfrom-json-results-work-on.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/7397044574408579681" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/7397044574408579681" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/Kl04Bwn_t18/making-xdmpfrom-json-results-work-on.html" title="Making xdmp:from-json Results Work on ML5 and ML6" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>2</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2013/01/making-xdmpfrom-json-results-work-on.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-5556303015406376454</id><published>2013-01-06T21:57:00.000-07:00</published><updated>2014-05-25T07:26:57.039-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="cts:uris" /><category scheme="http://www.blogger.com/atom/ns#" term="map:map" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic" /><title type="text">Cleaning Up Empty Directories</title><content type="html">If you are like me, you don't like clutter. Particularly I don't like a lot of empty directories in my MarkLogic Database. You could avoid the problem altogether by not having MarkLogic create the directories, but there is a level of convenience in being able to go directly to a file through WebDAV to edit it.&lt;br /&gt;&lt;br /&gt;So I came up with the following query to find the empty directories in your database. It uses cts:uris with the return type of map:map. Then I take the difference of the property uris and the document uris to get the list of directories only. Then I filter with an xdmp:estimate on the contents of the directory. If the xdmp:estimate is 0 then the directory is empty.&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="4472397" id="gist-4472397" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Finding Empty Directories in MarkLogic"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0-ml";&lt;br /&gt;&lt;br /&gt;let $directories-map := (cts:uris('/',('properties','map'),cts:directory-query('/','infinity'))&lt;br /&gt;-&lt;br /&gt;cts:uris('/',('document','map'),cts:directory-query('/','infinity')))     &lt;br /&gt;return map:keys($directories-map)[xdmp:estimate(cts:search(fn:collection(),cts:directory-query(.,'infinity'))) eq 0]&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/lvPhMyC1wHk" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/5556303015406376454/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2013/01/cleaning-up-empty-directories.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/5556303015406376454" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/5556303015406376454" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/lvPhMyC1wHk/cleaning-up-empty-directories.html" title="Cleaning Up Empty Directories" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2013/01/cleaning-up-empty-directories.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-8281464954584451589</id><published>2012-12-22T12:19:00.001-07:00</published><updated>2012-12-22T12:19:56.591-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><title type="text">When 100% Isn't Your Best</title><content type="html">Lately I've been looking at making code more compliant with XQuery standards that have been setup in a tool called Sonar that checks for compliance in our code. After closely looking through the code it has become obvious why there are varying levels of severity for each of the rules. Some rules are almost 100% of the time bad to break, if not 100% of the time (this is where different opinions come into play). Other rules, the tool should be simply engaging the developer to rethink the solution they came up with, offering tips of how the developer MIGHT better their code.&lt;br /&gt;&lt;br /&gt;If a complex code base has a 100% compliance with the set of rules, I would begin to wonder if the tool for verifying compliance was being properly used. With 100% compliance, I would suspect either the set of rules don't offer much in the way of engaging the developer or the tool is driving development instead of supplementing development. &lt;br /&gt;&lt;br /&gt;If we really just wanted to see the 100% on our Sonar dashboard, why don't we just write a tool that will make the offending code compliant for us? The obvious answer is that the impact on performance or outcome could not be completely understood by our tool. &lt;br /&gt;&lt;br /&gt;For example, it is generally bad practice to use the double forward slash (//) to find items in an XML document. Hopefully you know your XML structure well enough that you can provide the direct path (Sometimes you honestly don't know.). Even outside the instances where you don't know your structure enough to know the direct path to what your finding, the tool couldn't know that you have made the element you are looking for a root fragment which means you actually get increased performance using the // method within a cts:search.&lt;br /&gt;&lt;br /&gt;Also there is a matter of not having functions in predicates. This is generally a bad practice when retrieving content from the database, but it is often better after that point than the alternative of writing a FLWOR with only a simple where clause to filter out the sequence. It is one thing if the developer changes it to a FLWOR instead of a simple XPath for readability, but another if they are doing to be "compliant." &lt;br /&gt;&lt;br /&gt;Tools are just that, tools. Due to their limited capability, their measure of 100% doesn't always align with what is truly 100%. That being said, it always good to get in that 94+% range. An A is an A, right?&lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/NYDXOzHseVo" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/8281464954584451589/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2012/12/when-100-isnt-your-best.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/8281464954584451589" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/8281464954584451589" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/NYDXOzHseVo/when-100-isnt-your-best.html" title="When 100% Isn't Your Best" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2012/12/when-100-isnt-your-best.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-1726907203757775017</id><published>2012-12-18T12:21:00.000-07:00</published><updated>2014-05-25T07:27:14.475-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic" /><category scheme="http://www.blogger.com/atom/ns#" term="memorization" /><category scheme="http://www.blogger.com/atom/ns#" term="performance" /><title type="text">Server Level Memorization in MarkLogic</title><content type="html">There are some operations that are performed that are more expensive than what you would normally like to incur. If you have an operation like that needs to be repeated over and over again, that is where memorization comes in handy. &lt;br /&gt;&lt;br /&gt;Memorization is technique that can be use in purely functional languages or on code that is written to be purely functional. Code is purely functional when the output is always given set inputs.&lt;br /&gt;&lt;br /&gt;Like most things, memorization can come at a price. The decreased run time comes with an increase of memory consumption. If you use the technique too liberally it can end up hurting more than helping. That is why you need to be careful about not over-doing it.&lt;br /&gt;&lt;br /&gt;A good rule to follow when using memorization (beyond what the language already does for you at a lower level) is only use it when the operation is expensive and the number of unique input values are limited. If you try this technique and all your input value combinations are unique you gain nothing and actually degrade performance by performing more checks and using more memory than you need to.&lt;br /&gt;&lt;br /&gt;The following is an XQuery module to aide in memorization. It makes use of dynamic function calls, server fields to store results, and xdmp:describe and xdmp:quote to analyze inputs to ensure that inputs have not changed. If the inputs haven't changed for the provided label string and the operation has already been executed it returns the previously determined results. Otherwise it actually executes the function with its arguments and returns the results while storing it for use next time.&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="4314762" id="gist-4314762" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Memorization module in MarkLogic"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0-ml";&lt;br /&gt;&lt;br /&gt;module namespace memorize = "http://maxdewpoint.blogspot.com/memorize"; &lt;br /&gt;&lt;br /&gt;declare function memorize:memorize(&lt;br /&gt;$cache-label as xs:string, &lt;br /&gt;$fun as function(*)&lt;br /&gt;) {&lt;br /&gt;memorize:memorize($cache-label, $fun, ())&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function memorize:memorize(&lt;br /&gt;$cache-label as xs:string, &lt;br /&gt;$fun as function(*), &lt;br /&gt;$arg1 as item()*&lt;br /&gt;) {&lt;br /&gt;memorize:memorize($cache-label, $fun, $arg1, ())&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function memorize:memorize(&lt;br /&gt;$cache-label as xs:string, &lt;br /&gt;$fun as function(*), &lt;br /&gt;$arg1 as item()*, &lt;br /&gt;$arg2 as item()*&lt;br /&gt;) {&lt;br /&gt;memorize:memorize($cache-label, $fun, $arg1, $arg2, ())&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function memorize:memorize(&lt;br /&gt;$cache-label as xs:string, &lt;br /&gt;$fun as function(*), &lt;br /&gt;$arg1 as item()*, &lt;br /&gt;$arg2 as item()*, &lt;br /&gt;$arg3 as item()*&lt;br /&gt;) {&lt;br /&gt;memorize:memorize($cache-label, $fun, $arg1, $arg2, $arg3, ())&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function memorize:memorize(&lt;br /&gt;$cache-label as xs:string, &lt;br /&gt;$fun as function(*), &lt;br /&gt;$arg1 as item()*, &lt;br /&gt;$arg2 as item()*, &lt;br /&gt;$arg3 as item()*, &lt;br /&gt;$arg4 as item()*&lt;br /&gt;) {&lt;br /&gt;memorize:memorize($cache-label, $fun, $arg1, $arg2, $arg3, $arg4, ())&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function memorize:memorize(&lt;br /&gt;$cache-label as xs:string, &lt;br /&gt;$fun as function(*), &lt;br /&gt;$arg1 as item()*, &lt;br /&gt;$arg2 as item()*, &lt;br /&gt;$arg3 as item()*, &lt;br /&gt;$arg4 as item()*, &lt;br /&gt;$arg5 as item()*&lt;br /&gt;) {&lt;br /&gt;memorize:memorize($cache-label, $fun, $arg1, $arg2, $arg3, $arg4, $arg5, ())&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function memorize:memorize(&lt;br /&gt;$cache-label as xs:string, &lt;br /&gt;$fun as function(*), &lt;br /&gt;$arg1 as item()*, &lt;br /&gt;$arg2 as item()*, &lt;br /&gt;$arg3 as item()*, &lt;br /&gt;$arg4 as item()*, &lt;br /&gt;$arg5 as item()*, &lt;br /&gt;$arg6 as item()*&lt;br /&gt;) {&lt;br /&gt;memorize:memorize($cache-label, $fun, $arg1, $arg2, $arg3, $arg4, $arg5, $arg6, ())&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function memorize:memorize(&lt;br /&gt;$cache-label as xs:string, &lt;br /&gt;$fun as function(*), &lt;br /&gt;$arg1 as item()*, &lt;br /&gt;$arg2 as item()*, &lt;br /&gt;$arg3 as item()*, &lt;br /&gt;$arg4 as item()*, &lt;br /&gt;$arg5 as item()*, &lt;br /&gt;$arg6 as item()*, &lt;br /&gt;$arg7 as item()*&lt;br /&gt;) {&lt;br /&gt;memorize:memorize($cache-label, $fun, $arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7, ())&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function memorize:memorize(&lt;br /&gt;$cache-label as xs:string, &lt;br /&gt;$fun as function(*), &lt;br /&gt;$arg1 as item()*, &lt;br /&gt;$arg2 as item()*, &lt;br /&gt;$arg3 as item()*, &lt;br /&gt;$arg4 as item()*, &lt;br /&gt;$arg5 as item()*, &lt;br /&gt;$arg6 as item()*, &lt;br /&gt;$arg7 as item()*, &lt;br /&gt;$arg8 as item()*&lt;br /&gt;) {&lt;br /&gt;let $cache-hash := memorize:_cache-hash($fun, $arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7, $arg8),&lt;br /&gt;$stored-value := xdmp:get-server-field(fn:concat('{http://maxdewpoint.blogspot.com/memorize}',$cache-label))&lt;br /&gt;return&lt;br /&gt;if ($stored-value instance of map:map) &lt;br /&gt;then&lt;br /&gt;if (map:get(&lt;br /&gt;$stored-value,&lt;br /&gt;'cache-hash'&lt;br /&gt;)&lt;br /&gt;eq&lt;br /&gt;$cache-hash         &lt;br /&gt;)&lt;br /&gt;then map:get(&lt;br /&gt;$stored-value,&lt;br /&gt;'value'&lt;br /&gt;)&lt;br /&gt;else&lt;br /&gt;memorize:_memorize($cache-label, $cache-hash, $fun, $arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7, $arg8)&lt;br /&gt;else&lt;br /&gt;memorize:_memorize($cache-label, $cache-hash, $fun, $arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7, $arg8)&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function memorize:_memorize(&lt;br /&gt;$cache-label as xs:string, &lt;br /&gt;$cache-hash as xs:string, &lt;br /&gt;$fun as function(*), &lt;br /&gt;$arg1 as item()*, &lt;br /&gt;$arg2 as item()*, &lt;br /&gt;$arg3 as item()*, &lt;br /&gt;$arg4 as item()*, &lt;br /&gt;$arg5 as item()*, &lt;br /&gt;$arg6 as item()*, &lt;br /&gt;$arg7 as item()*, &lt;br /&gt;$arg8 as item()*&lt;br /&gt;) {&lt;br /&gt;map:get(&lt;br /&gt;(: set server field with map:map containing input hash and output value :)&lt;br /&gt;xdmp:set-server-field(&lt;br /&gt;fn:concat('{http://maxdewpoint.blogspot.com/memorize}',$cache-label),&lt;br /&gt;map:map()[&lt;br /&gt;map:put(.,'cache-hash',$cache-hash),&lt;br /&gt;map:put(.,&lt;br /&gt;'value',&lt;br /&gt;switch(fn:function-arity($fun))&lt;br /&gt;case 0 return $fun()&lt;br /&gt;case 1 return $fun($arg1)    &lt;br /&gt;case 2 return $fun($arg1,$arg2)    &lt;br /&gt;case 3 return $fun($arg1,$arg2,$arg3)&lt;br /&gt;case 4 return $fun($arg1,$arg2,$arg3,$arg4)&lt;br /&gt;case 5 return $fun($arg1,$arg2,$arg3,$arg4,$arg5)&lt;br /&gt;case 6 return $fun($arg1,$arg2,$arg3,$arg4,$arg5,$arg6)&lt;br /&gt;case 7 return $fun($arg1,$arg2,$arg3,$arg4,$arg5,$arg6,$arg7)&lt;br /&gt;case 8 return $fun($arg1,$arg2,$arg3,$arg4,$arg5,$arg6,$arg7,$arg8)&lt;br /&gt;default return 'too many arguments'&lt;br /&gt;),&lt;br /&gt;fn:true()&lt;br /&gt;]&lt;br /&gt;),&lt;br /&gt;'value'&lt;br /&gt;)&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function memorize:_cache-hash(&lt;br /&gt;$fun as function(*), &lt;br /&gt;$arg1 as item()*, &lt;br /&gt;$arg2 as item()*, &lt;br /&gt;$arg3 as item()*, &lt;br /&gt;$arg4 as item()*, &lt;br /&gt;$arg5 as item()*, &lt;br /&gt;$arg6 as item()*, &lt;br /&gt;$arg7 as item()*, &lt;br /&gt;$arg8 as item()*&lt;br /&gt;) {&lt;br /&gt;(: Using sha1 to hash and the base64 option for a shorter string. :)&lt;br /&gt;xdmp:hmac-sha1(&lt;br /&gt;'memorize',&lt;br /&gt;fn:string-join(&lt;br /&gt;($fun,'|',&lt;br /&gt;$arg1,'|',&lt;br /&gt;$arg2,'|',&lt;br /&gt;$arg3,'|', &lt;br /&gt;$arg4,'|',&lt;br /&gt;$arg5,'|',&lt;br /&gt;$arg6,'|',&lt;br /&gt;$arg7,'|',&lt;br /&gt;$arg8) ! (&lt;br /&gt;typeswitch(.)&lt;br /&gt;(: if it is a function ensure we get the long hand namespaced name :)&lt;br /&gt;case function(*) return&lt;br /&gt;fn:concat(xdmp:key-from-QName(fn:function-name(.)),'#',fn:string(fn:function-arity(.)))&lt;br /&gt;(: want to use xdmp:quote if it is XML contained in the database since the value could change, but the description would remain the same. :)&lt;br /&gt;case node() return&lt;br /&gt;if (fn:exists(fn:base-uri(.)))&lt;br /&gt;then xdmp:quote(.)&lt;br /&gt;else xdmp:describe(., (),())),&lt;br /&gt;(: by default use xdmp:describe since with no sequence limit and no character limit :)&lt;br /&gt;default return&lt;br /&gt;xdmp:describe(., (),())),&lt;br /&gt;''&lt;br /&gt;),&lt;br /&gt;'base64'&lt;br /&gt;)&lt;br /&gt;};&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/ub6WIRk1RQc" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/1726907203757775017/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2012/12/server-level-memorization-in-marklogic.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/1726907203757775017" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/1726907203757775017" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/ub6WIRk1RQc/server-level-memorization-in-marklogic.html" title="Server Level Memorization in MarkLogic" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2012/12/server-level-memorization-in-marklogic.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-4542312453138186632</id><published>2012-12-08T10:34:00.000-07:00</published><updated>2014-05-25T07:27:32.060-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="copy" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic 6" /><category scheme="http://www.blogger.com/atom/ns#" term="memory" /><category scheme="http://www.blogger.com/atom/ns#" term="validate lax" /><category scheme="http://www.blogger.com/atom/ns#" term="xdmp:copy-on-validate" /><category scheme="http://www.blogger.com/atom/ns#" term="xQuery" /><category scheme="http://www.blogger.com/atom/ns#" term="XQuery 3.0" /><title type="text">Copy XML with Validate Lax </title><content type="html">Sometimes you might like to efficiently copy a chuck of XML and have it completely disassociated from its parent node. Fortunately, that is exactly what the validate lax expression does according to the XQuery standards (It also does validation on any schema in the context of the XQuery, but your XML should either match the schema or not have a schema for the document in context anyway, right?). &lt;br /&gt;&lt;br /&gt;However in MarkLogic with XQuery version '1.0-ml' the standard isn't followed in this case. If you run the following code in QConsole, you will see that '1.0-ml' will merely return the same node back to you if it is determined to be valid. Compare that to running the same code with version '1.0'. &lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="4241093" id="gist-4241093" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Validate Lax 1.0-ml and 1.0 Example"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0-ml";&lt;br /&gt;&lt;br /&gt;let $child-element := (element div { element a {}})/a,&lt;br /&gt;$lax-validated-child := validate lax { $child-element }&lt;br /&gt;return $lax-validated-child is $child-element&lt;br /&gt;;&lt;br /&gt;xquery version "1.0";&lt;br /&gt;&lt;br /&gt;let $child-element := (element div { element a {}})/a,&lt;br /&gt;$lax-validated-child := validate lax { $child-element }&lt;br /&gt;return $lax-validated-child is $child-element&lt;/div&gt;&lt;br /&gt;Now you might think it is not worth it to lose all the other MarkLogic goodness. Never fear, you can get most of the MarkLogic goodness back using the following:&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="4241110" id="gist-4241110" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Valid XQuery 1.0 With MarkLogic Enhancements"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0";&lt;br /&gt;(: or xquery version '3.0' if want those functions in ML 6:)&lt;br /&gt;&lt;br /&gt;declare namespace cts = "http://marklogic.com/cts";&lt;br /&gt;declare namespace xdmp = "http://marklogic.com/xdmp";&lt;br /&gt;declare namespace map = "http://marklogic.com/xdmp/map";&lt;br /&gt;&lt;br /&gt;declare option xdmp:mapping "true";&lt;br /&gt;&lt;br /&gt;(: Note that you now need the fn:collection() or fn:doc()  :)&lt;br /&gt;cts:search(fn:collection()/article, cts:and-query(()))[1]&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt; You can also use 'declare option xdmp:copy-on-validate "true";' in version 1.0-ml.&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/2ddSZAX1PQc" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/4542312453138186632/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2012/12/copy-xml-with-validate-lax.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/4542312453138186632" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/4542312453138186632" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/2ddSZAX1PQc/copy-xml-with-validate-lax.html" title="Copy XML with Validate Lax " /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2012/12/copy-xml-with-validate-lax.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-7028914106102595946</id><published>2012-11-06T07:35:00.000-07:00</published><updated>2012-11-06T09:08:43.303-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="politics" /><category scheme="http://www.blogger.com/atom/ns#" term="software" /><title type="text">If the Software World Ran Like U.S. Politics</title><content type="html">In celebration of “The political calls and ads are finally coming to an end” day, I thought I would share a little analogy that I have about if the software world were run like the U.S. Political system. (I know, I live in Utah, not exactly a swing state. In my defense, though, the Mia Love vs. Jim Matheson contest has gotten pretty heated and tiresome. Also, we get plenty of Romney vs. Obama through those “series of tubes” called the Internet.)&lt;br /&gt;&lt;br /&gt;Imagine a world where software engineers and architects were elected to their position. Beyond that, the general population felt that, rather than just being responsible for electing those engineers and architects who qualified, they needed to be involved with the details of how those they elected went about their work. Campaigns would be put together based on the camp in which people fell.&lt;br /&gt;&lt;br /&gt;The current Google administration would blame the current problems on the legacy Microsoft APIs of the former Microsoft administration. Meanwhile, Microsoft would constantly try to remind the people of the 'good old days' of Windows 3.1 and how they, like how Lincoln freed the blacks with the abolition of slavery, had freed the bean counters with Excel Spreadsheets. Apple would be attacked for catering to the top fill-in-the-blank percent of users, while Google would be attacked for the redistribution of mobile swagger with their cheap, but effective Android mobile devices.&lt;br /&gt;&lt;br /&gt;Journalists would write of the “evils” of functional languages and praise those of the object oriented world. Op eds would be written to inform the population that a vote for MarkLogic is a vote for Microsoft. Watch dog groups would be formed to scrutinize should a for loop be used when it is “obvious” a while loop was the loop of choice. Every four years, should the mood of the nation change, the current architects would be replaced just as they were starting to replace the previously installed systems.&lt;br /&gt;&lt;br /&gt;Vendors would form lobbyist groups and promise the world in order to ensure that money was funneled their way. These vendors would also vie for exemptions from the technical mandates handed down from on high. All these dealings would occur behind closed doors out the view of the public eye.&lt;br /&gt;&lt;br /&gt;It would be a nightmare to develop and architect software according to the knowledge of the general population. When filling a software engineer position, the best companies hire those that are qualified and can be trusted in that position. I don't pretend to know all the solutions to all the political issues, just as I would be put out by 'non-technical people' pretending to know all the answers to all the technical issues. So why can't we elect people to office, simply knowing they are qualified and can be trusted?&lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/S37KtsPufMw" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/7028914106102595946/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2012/11/if-software-world-ran-like-us-politics.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/7028914106102595946" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/7028914106102595946" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/S37KtsPufMw/if-software-world-ran-like-us-politics.html" title="If the Software World Ran Like U.S. Politics" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2012/11/if-software-world-ran-like-us-politics.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-4981547429216579947</id><published>2012-10-06T11:31:00.000-06:00</published><updated>2014-05-25T07:27:48.992-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="fn:function-arity" /><category scheme="http://www.blogger.com/atom/ns#" term="fn:function-lookup" /><category scheme="http://www.blogger.com/atom/ns#" term="fn:function-name" /><category scheme="http://www.blogger.com/atom/ns#" term="Higher Order Functions" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic 6" /><title type="text">Higher Order Functions in MarkLogic 6</title><content type="html">Lately I've been playing around with higher order functions in MarkLogic 6. After a while I came up with some code for executing XQuery based off of XML. The first example that I give shows how I can use XML to configure how a function is called. This example shows XML determining how xdmp:tidy is called. &lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="3845472" id="gist-3845472" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Higher Order Example 1"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0-ml";&lt;br /&gt;&lt;br /&gt;declare function local:html-handler($html as xs:string) {&lt;br /&gt;local:html-handler($html, fn:false())&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:html-handler($html as xs:string, $show-tidy-warnings as xs:boolean) {&lt;br /&gt;local:html-handler($html, $show-tidy-warnings, ())&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:html-handler($html as xs:string, $show-tidy-warnings as xs:boolean, $options as xs:string*) {&lt;br /&gt;xdmp:tidy($html,&lt;br /&gt;&amp;lt;options xmlns="xdmp:tidy"&amp;gt;{&lt;br /&gt;$options ! (element {fn:QName("xdmp:tidy",fn:substring-before(.,'='))} {fn:substring-after(.,'=')} )&lt;br /&gt;}&amp;lt;/options&amp;gt;)[$show-tidy-warnings or fn:position() eq 2]&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;let $html := "&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;My page&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;br /&gt;let $execution-descriptor := &lt;br /&gt;&amp;lt;execution-descriptor xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&amp;gt;&lt;br /&gt;&amp;lt;function ns="http://www.w3.org/2005/xquery-local-functions" arity="3"&amp;gt;html-handler&amp;lt;/function&amp;gt;&lt;br /&gt;&amp;lt;arg-sets&amp;gt;&lt;br /&gt;&amp;lt;arg-set&amp;gt;&lt;br /&gt;&amp;lt;item xsi:type="xs:boolean"&amp;gt;true&amp;lt;/item&amp;gt;&lt;br /&gt;&amp;lt;/arg-set&amp;gt;&lt;br /&gt;&amp;lt;arg-set&amp;gt;&lt;br /&gt;&amp;lt;item xsi:type="xs:string"&amp;gt;indent=yes&amp;lt;/item&amp;gt;&lt;br /&gt;&amp;lt;item xsi:type="xs:string"&amp;gt;indent-spaces=2&amp;lt;/item&amp;gt;&lt;br /&gt;&amp;lt;item xsi:type="xs:string"&amp;gt;markup=yes&amp;lt;/item&amp;gt;&lt;br /&gt;&amp;lt;/arg-set&amp;gt;&lt;br /&gt;&amp;lt;/arg-sets&amp;gt;&lt;br /&gt;&amp;lt;/execution-descriptor&amp;gt;&lt;br /&gt;&lt;br /&gt;let $funct := fn:function-lookup(fn:QName($execution-descriptor/function/@ns,$execution-descriptor/function),$execution-descriptor/function/@arity)&lt;br /&gt;&lt;br /&gt;return &lt;br /&gt;switch(fn:function-arity($funct))&lt;br /&gt;case 1 return $funct($html)&lt;br /&gt;case 2 return $funct($html,$execution-descriptor/arg-sets/arg-set[1]/item/fn:data(.))&lt;br /&gt;case 3 return $funct($html,$execution-descriptor/arg-sets/arg-set[1]/item/fn:data(.),$execution-descriptor/arg-sets/arg-set[2]/item/fn:data(.))&lt;br /&gt;default return ()&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;In the previous case there might not be any obvious power to it. You could easily just have XML that could change the options you pass to xdmp:tidy already. So the question is, "What is the big deal?" Hopefully the following example expresses the power a little more.&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="3845488" id="gist-3845488" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Higher Order Example 2"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0-ml";&lt;br /&gt;&lt;br /&gt;import module namespace mem  = "http://maxdewpoint.blogspot.com/memory-operations" at "/MaxDewPoint/memory-operations.xqy";&lt;br /&gt;&lt;br /&gt;declare namespace xs="http://www.w3.org/2001/XMLSchema";&lt;br /&gt;declare namespace xsi="http://www.w3.org/2001/XMLSchema-instance";&lt;br /&gt;&lt;br /&gt;declare function local:innermost($nodes as node()*) as node()* {&lt;br /&gt;$nodes except $nodes/ancestor::node()&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:descriptor-executor($descriptor as element(execution-descriptor)) {&lt;br /&gt;let $child-descriptors := $descriptor//execution-descriptor&lt;br /&gt;return &lt;br /&gt;if (fn:exists($child-descriptors))&lt;br /&gt;then &lt;br /&gt;local:descriptor-executor(mem:transform(&lt;br /&gt;local:innermost($child-descriptors), &lt;br /&gt;function ($node as node()) as node()* {&lt;br /&gt;local:wrap-result(local:descriptor-execute($node))&lt;br /&gt;}&lt;br /&gt;))&lt;br /&gt;else&lt;br /&gt;local:descriptor-execute($descriptor)&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:descriptor-execute($descriptor as element(execution-descriptor)) {&lt;br /&gt;let $funct := fn:function-lookup(fn:QName($descriptor/function/@ns,$descriptor/function),$descriptor/function/@arity)&lt;br /&gt;return&lt;br /&gt;switch(fn:function-arity($funct))&lt;br /&gt;case 0 return &lt;br /&gt;$funct()&lt;br /&gt;case 1 return &lt;br /&gt;$funct(local:process-arg-set($descriptor/arg-sets/arg-set[1]))&lt;br /&gt;case 2 return &lt;br /&gt;$funct(local:process-arg-set($descriptor/arg-sets/arg-set[1]),local:process-arg-set($descriptor/arg-sets/arg-set[2]))&lt;br /&gt;case 3 return &lt;br /&gt;$funct(local:process-arg-set($descriptor/arg-sets/arg-set[1]),local:process-arg-set($descriptor/arg-sets/arg-set[2]),local:process-arg-set($descriptor/arg-sets/arg-set[3]))&lt;br /&gt;default return ()&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:process-arg-set($arg-set as element(arg-set)) {&lt;br /&gt;$arg-set/* !&lt;br /&gt;(&lt;br /&gt;typeswitch(.)&lt;br /&gt;case element(item) return fn:data(.)&lt;br /&gt;case element(node) return xdmp:value(fn:string(.))&lt;br /&gt;case element(function-ref) return fn:function-lookup(fn:QName(./@ns,.),./@arity)&lt;br /&gt;default return ()&lt;br /&gt;)&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:wrap-result($result as item()*) {&lt;br /&gt;$result !&lt;br /&gt;( &lt;br /&gt;typeswitch(.) &lt;br /&gt;case node() return element node {xdmp:describe(.,(),())}&lt;br /&gt;case function(*) return element function-ref { attribute arity {fn:function-arity(.)}, fn:function-name(.) ! (attribute ns {fn:namespace-uri-from-QName(.)}, fn:local-name-from-QName(.))}&lt;br /&gt;default return element item { attribute xsi:type {local:determine-type(.)},fn:data(.)}&lt;br /&gt;)&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:determine-type($item as item()) {&lt;br /&gt;typeswitch($item) &lt;br /&gt;case xs:dateTime return "xs:dateTime"&lt;br /&gt;case xs:date return "xs:date"&lt;br /&gt;case xs:duration return "xs:duration"&lt;br /&gt;case xs:float return "xs:float"&lt;br /&gt;case xs:double return "xs:double"&lt;br /&gt;case xs:decimal return "xs:decimal"&lt;br /&gt;case xs:integer return "xs:integer"&lt;br /&gt;case xs:boolean return "xs:boolean"&lt;br /&gt;case xs:QName return "xs:QName"&lt;br /&gt;case xs:integer return "xs:integer"&lt;br /&gt;default return "xs:untypedAtomic"&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;local:descriptor-executor(&lt;execution-descriptor xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;&lt;br /&gt;&amp;lt;function ns="http://www.w3.org/2005/xpath-functions" arity="2"&amp;gt;string-join&amp;lt;/function&amp;gt;&lt;br /&gt;&amp;lt;arg-sets&amp;gt;&lt;br /&gt;&amp;lt;arg-set&amp;gt;&lt;br /&gt;&amp;lt;execution-descriptor&amp;gt;&lt;br /&gt;&amp;lt;function ns="http://www.w3.org/2005/xpath-functions" arity="3"&amp;gt;map-pairs&amp;lt;/function&amp;gt;&lt;br /&gt;&amp;lt;arg-sets&amp;gt;&lt;br /&gt;&amp;lt;arg-set&amp;gt;&lt;br /&gt;&amp;lt;function-ref ns="http://www.w3.org/2005/xpath-functions" arity="2"&amp;gt;concat&amp;lt;/function-ref&amp;gt;&lt;br /&gt;&amp;lt;/arg-set&amp;gt;&lt;br /&gt;&amp;lt;arg-set&amp;gt;&lt;br /&gt;&amp;lt;item xsi:type="xs:string"&amp;gt;indent=&amp;lt;/item&amp;gt;&lt;br /&gt;&amp;lt;item xsi:type="xs:string"&amp;gt;indent-spaces=&amp;lt;/item&amp;gt;&lt;br /&gt;&amp;lt;item xsi:type="xs:string"&amp;gt;markup=&amp;lt;/item&amp;gt;&lt;br /&gt;&amp;lt;/arg-set&amp;gt;&lt;br /&gt;&amp;lt;arg-set&amp;gt;&lt;br /&gt;&amp;lt;item xsi:type="xs:string"&amp;gt;yes&amp;lt;/item&amp;gt;&lt;br /&gt;&amp;lt;item xsi:type="xs:string"&amp;gt;2&amp;lt;/item&amp;gt;&lt;br /&gt;&amp;lt;item xsi:type="xs:string"&amp;gt;yes&amp;lt;/item&amp;gt;&lt;br /&gt;&amp;lt;/arg-set&amp;gt;&lt;br /&gt;&amp;lt;/arg-sets&amp;gt;&lt;br /&gt;&amp;lt;/execution-descriptor&amp;gt;&lt;br /&gt;&amp;lt;/arg-set&amp;gt;&lt;br /&gt;&amp;lt;arg-set&amp;gt;&lt;br /&gt;&amp;lt;item xsi:type="xs:string"&amp;gt;;&amp;lt;/item&amp;gt;&lt;br /&gt;&amp;lt;/arg-set&amp;gt;&lt;br /&gt;&amp;lt;/arg-sets&amp;gt;&lt;br /&gt;&amp;lt;/execution-descriptor&amp;gt;)&lt;/execution-descriptor&gt;&lt;/div&gt;&lt;br /&gt;In the last example, the output is completely determined by the XML. You could play around with this code in the QConsole, changing the execution-descriptor to whatever it is you want to execute. Try running the following in the QConsole. Pretty neat...&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="3845595" id="gist-3845595" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Higher Order Example 3"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;local:descriptor-executor(&amp;lt;execution-descriptor xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&amp;gt;&lt;br /&gt;&amp;lt;function ns="http://maxdewpoint.blogspot.com/memory-operations" arity="2"&amp;gt;insert-child&amp;lt;/function&amp;gt;&lt;br /&gt;&amp;lt;arg-sets&amp;gt;&lt;br /&gt;&amp;lt;arg-set&amp;gt;{local:wrap-result(fn:collection()[1]/*)}&amp;lt;/arg-set&amp;gt;&lt;br /&gt;&amp;lt;arg-set&amp;gt;{local:wrap-result(attribute new-attribute{"added"})}&amp;lt;/arg-set&amp;gt;&lt;br /&gt;&amp;lt;/arg-sets&amp;gt;&lt;br /&gt;&amp;lt;/execution-descriptor&amp;gt;)&lt;/div&gt;&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/-HP0Er0hSV0" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/4981547429216579947/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2012/10/higher-order-functions-in-marklogic-6.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/4981547429216579947" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/4981547429216579947" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/-HP0Er0hSV0/higher-order-functions-in-marklogic-6.html" title="Higher Order Functions in MarkLogic 6" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2012/10/higher-order-functions-in-marklogic-6.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-5928207757080493559</id><published>2012-09-27T07:55:00.000-06:00</published><updated>2012-09-27T07:55:12.356-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Aggregate User Defined Functions" /><category scheme="http://www.blogger.com/atom/ns#" term="C/C++" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic 6" /><category scheme="http://www.blogger.com/atom/ns#" term="plugin" /><category scheme="http://www.blogger.com/atom/ns#" term="regular expressions" /><title type="text">My First MarkLogic Aggregate User-Defined Function</title><content type="html">I wrote my first &lt;a href="http://docs.marklogic.com/guide/app-dev/aggregateUDFs"&gt;Aggregate User-Defined Function&lt;/a&gt; in MarkLogic. There were a couple stumbling blocks that I encountered and had to brush up on my C/C++, but I think it was pretty straight forward, thanks to MarkLogic's documentation and examples.&lt;br /&gt;&lt;br /&gt;The native function that I created compares regular expressions against a lexicon of string values and returns the matches. The results were very encouraging, which I will cover later. First I'll address my stumbling blocks.&lt;br /&gt;&lt;br /&gt;My first stumbling block, was a fairly easy and simple one. I didn't pay enough attention to the namespace I used to install my plugin and then proceeded to try to call my plugin without the namespace I indicated. Following the example provided by MarkLogic, I used 'native' as the namespace and then proceeded to call it without the namespace like "regex-audf" instead of the correct way "native/regex-audf".&lt;br /&gt;&lt;br /&gt;My second issue encountered was not paying attention to the &lt;a href="http://docs.marklogic.com/guide/app-dev/aggregateUDFs"&gt;Object Lifetime&lt;/a&gt;. What my plugin does is a bit different from the examples provided by MarkLogic in that I'm accumulating strings that match a regular expression, instead of a running tally of some sort.&lt;br /&gt;&lt;br /&gt;Being over eager in trying to clean up after myself, I originally tried to delete the strings I accumulated in the close function of my AUDF. I quickly realized that wouldn't work and subsequently came across the following in the documentation: "The clone and close methods of your aggregate UDF may be called many times per job."&lt;br /&gt;&lt;br /&gt;You can take a look at my code on &lt;a href="https://github.com/ryanjdew/regex-audf/blob/master/RegexPlugin.cpp"&gt;GitHub&lt;/a&gt;. If you notice things obviously wrong, be kind, I've been out of C++ for a while so I could have easily missed something(s). :)&lt;br /&gt;&lt;br /&gt;Here are some performance numbers using my plugin:&lt;br /&gt;&lt;br /&gt;cts:values fn:matches&lt;br /&gt;PT0.005568S&lt;br /&gt;regex audf&lt;br /&gt;PT0.001605S&lt;br /&gt;cts:values reverse fn:matches&lt;br /&gt;PT0.00506S&lt;br /&gt;reverse regex audf&lt;br /&gt;PT0.026693S&lt;br /&gt;&lt;br /&gt;You will notice that right now my 'reverse regex audf' which identifies regular expressions in a lexicon that match a passed parameter, is actually much slower than using fn:matches. Perhaps I will need to create my own &lt;a href="http://docs.marklogic.com/guide/app-dev/aggregateUDFs#id_91381"&gt;Custom Allocator&lt;/a&gt; to get around that issue. So much to do, so little time...&lt;br /&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/JxmTk0sfOPY" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/5928207757080493559/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2012/09/my-first-marklogic-aggregate-user.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/5928207757080493559" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/5928207757080493559" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/JxmTk0sfOPY/my-first-marklogic-aggregate-user.html" title="My First MarkLogic Aggregate User-Defined Function" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2012/09/my-first-marklogic-aggregate-user.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-5417631863542804235</id><published>2012-09-21T20:26:00.001-06:00</published><updated>2014-05-25T07:29:56.810-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Inline Functions" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic 6" /><category scheme="http://www.blogger.com/atom/ns#" term="memory" /><category scheme="http://www.blogger.com/atom/ns#" term="XML" /><category scheme="http://www.blogger.com/atom/ns#" term="XQuery 3.0" /><title type="text">Memory Updates By Passing Function References</title><content type="html">I was so excited about the new ability to pass function references I had to add use it in my XQuery-XML-Memory-Operations library that I created. The version is now at 0.5.0, which only works with MarkLogic 6. If you still need it to work with older versions of MarkLogic you can use the v0.4.2 tag.&lt;br /&gt;&lt;br /&gt;You will also notice that mem:copy($node) now returns a string which is your transaction id. The transaction will need to be passed as the first parameter to any operations you want to perform and then to the mem:execute($transaction-id) function when ready. It actually looks pretty slick when used with the map operator (!).&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="3764915" id="gist-3764915" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="In Memory Transform With Inline Function"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0-ml";&lt;br /&gt;import module namespace mem = "http://maxdewpoint.blogspot.com/memory-operations" at "/memory-operations.xqy";&lt;br /&gt;&lt;br /&gt;declare variable $test-xml := &amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;title&amp;gt;This is a title&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;!-- old comment --&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&amp;lt;div id="div1"&amp;gt;&lt;br /&gt;&amp;lt;p class="p1"&amp;gt;&amp;lt;!-- old comment --&amp;gt;This is a paragraph.&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;p class="p2"&amp;gt;This is a paragraph.&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;p class="p3"&amp;gt;This is a paragraph.&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;p class="p4"&amp;gt;This is a paragraph.&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;p class="p5"&amp;gt;This is a paragraph.&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div id="div2"&amp;gt;&lt;br /&gt;&amp;lt;p class="p1"&amp;gt;This is a paragraph.&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;p class="p2"&amp;gt;This is a paragraph.&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;p class="p3"&amp;gt;This is a paragraph.&amp;lt;!-- old comment --&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;p class="p4"&amp;gt;This is a paragraph.&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;p class="p5"&amp;gt;This is a paragraph.&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;;&lt;br /&gt;&lt;br /&gt;mem:copy($test-xml) !          &lt;br /&gt;(&lt;br /&gt;mem:transform(.,$test-xml/head/title,function($node as node()) as node()* {element new-title {"This is so awesome!"}}),&lt;br /&gt;mem:execute(.) &lt;br /&gt;)&lt;/div&gt;&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/JrMqPyfAedg" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/5417631863542804235/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2012/09/memory-updates-by-passing-function.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/5417631863542804235" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/5417631863542804235" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/JrMqPyfAedg/memory-updates-by-passing-function.html" title="Memory Updates By Passing Function References" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2012/09/memory-updates-by-passing-function.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-5272277972812634911</id><published>2012-09-19T06:27:00.001-06:00</published><updated>2014-05-25T07:30:19.245-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Clark Notation" /><category scheme="http://www.blogger.com/atom/ns#" term="default for external variables" /><category scheme="http://www.blogger.com/atom/ns#" term="fn:function-arity" /><category scheme="http://www.blogger.com/atom/ns#" term="fn:function-name" /><category scheme="http://www.blogger.com/atom/ns#" term="map operator" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic 6" /><category scheme="http://www.blogger.com/atom/ns#" term="xdmp:describe" /><category scheme="http://www.blogger.com/atom/ns#" term="xdmp:functions" /><category scheme="http://www.blogger.com/atom/ns#" term="XPath 3.0" /><category scheme="http://www.blogger.com/atom/ns#" term="XQuery 3.0" /><title type="text">More MarkLogic 6 Goodness</title><content type="html">&lt;h3&gt;&lt;a href="http://www.w3.org/TR/xquery-30/#id-string-concat-expr"&gt;String Concatenation&lt;/a&gt;&lt;/h3&gt;You can now do string concatenation with double pipes (||).&lt;br /&gt;&lt;h3&gt;&lt;a href="http://www.w3.org/TR/xquery-30/#id-map-operator"&gt;Map Operator&lt;/a&gt;&lt;/h3&gt;The map operator (!) is added. This allows for simple iteration over atomic types much like the / in XPath with nodes.&lt;br /&gt;&lt;h3&gt;&lt;a href="http://www.w3.org/TR/xquery-30/#id-variable-declarations"&gt;Default Values For External Variables&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;Now you can provide a default value for external variables.&amp;nbsp;&lt;/div&gt;&lt;h3&gt;Clark Notation For Calling Functions&lt;/h3&gt;&lt;div&gt;This allows you to provide a fully qualified namespace instead of having to declare a namespace. For example,&amp;nbsp;Q{http://marklogic.com/xdmp}functions() instead of xdmp:functions()&lt;/div&gt;&lt;h3&gt;Fun With Functions&lt;/h3&gt;&lt;div&gt;Speaking of xdmp:functions() that is a pretty cool function that will return all functions that are in scope.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Below I provide an example that makes use of these new found features.&lt;/div&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="3749367" id="gist-3749367" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="New MarkLogic 6 Features"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "3.0";&lt;br /&gt;&lt;br /&gt;(: Default vaules for external variables :)&lt;br /&gt;declare variable $item external := ();&lt;br /&gt;&lt;br /&gt;(: Specify the namespace with Q followed by clark notation :)&lt;br /&gt;Q{http://marklogic.com/xdmp}functions() (: xdmp:functions returns all functions in scope :) ! &lt;br /&gt;(: Support for the map operator :) &lt;br /&gt;element function {&lt;br /&gt;element name {fn:function-name(.)},&lt;br /&gt;element arity {fn:function-arity(.)},&lt;br /&gt;element describe {Q{http://marklogic.com/xdmp}describe(.)}&lt;br /&gt;}&lt;/div&gt;&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/wrlG9v3ef8E" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/5272277972812634911/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2012/09/more-marklogic-6-goodness.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/5272277972812634911" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/5272277972812634911" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/wrlG9v3ef8E/more-marklogic-6-goodness.html" title="More MarkLogic 6 Goodness" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2012/09/more-marklogic-6-goodness.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-2694174005121752055</id><published>2012-09-17T07:41:00.000-06:00</published><updated>2012-09-17T07:52:05.697-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Aggregate User Defined Functions" /><category scheme="http://www.blogger.com/atom/ns#" term="Dynamic Function Calls" /><category scheme="http://www.blogger.com/atom/ns#" term="Inline Functions" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic 6" /><category scheme="http://www.blogger.com/atom/ns#" term="Switch Case Expression" /><category scheme="http://www.blogger.com/atom/ns#" term="try catch" /><category scheme="http://www.blogger.com/atom/ns#" term="XPath 3.0" /><category scheme="http://www.blogger.com/atom/ns#" term="XQuery 3.0" /><title type="text">MarkLogic 6.0 Released</title><content type="html">Highlights include the following:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Now can specify the XQuery version as "3.0" (Note that not all of XQuery 3.0 is supported yet and seems to be the same as "1.0-ml" at this point.)&lt;/li&gt;&lt;li&gt;Many new XPath functions added from the &lt;a href="http://www.w3.org/TR/xpath-functions-30/"&gt;XPath 3.0&lt;/a&gt; specs.&lt;/li&gt;&lt;li&gt;Now have the &lt;a href="http://www.w3.org/TR/xquery-30/#id-switch"&gt;switch case expression&lt;/a&gt; available for comparing atomic types&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.w3.org/TR/xquery-30/#id-inline-func"&gt;Inline functions&lt;/a&gt;/&lt;a href="http://www.w3.org/TR/xquery-30/#id-dynamic-function-invocation"&gt;Dynamic function calls&lt;/a&gt; (This is huge! Especially when coupled the &lt;a href="http://www.w3.org/TR/xpath-functions-30/#higher-order-functions"&gt;higher order XPath functions&lt;/a&gt; added.)&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.w3.org/TR/xquery-30/#id-try-catch"&gt;Try/Catch&lt;/a&gt; statements that align with the XQuery 3.0 spec.&lt;/li&gt;&lt;li&gt;&lt;a href="http://docs.marklogic.com/guide/app-dev/aggregateUDFs"&gt;Aggregate User Defined Functions&lt;/a&gt; (Can't wait to start digging into that!)&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;This was a really great release for MarkLogic. I'm excited to get playing around with these new features. I must say MarkLogic caught me off guard. I was hoping to have more XQuery 3.0 coolness ready before they made a release like this.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A few things to look forward to in the future:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&amp;nbsp;Some XQuery 3.0 FLWOR love&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.w3.org/TR/xquery-30/#id-windows"&gt;Window Clauses&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.w3.org/TR/xquery-30/#id-xquery-for-clause"&gt;Allowing Empty&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.w3.org/TR/xquery-30/#id-group-by"&gt;Group By&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.w3.org/TR/xquery-30/#id-count"&gt;Count&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/T5DwMZiOq9I" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/2694174005121752055/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2012/09/marklogic-60-released.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/2694174005121752055" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/2694174005121752055" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/T5DwMZiOq9I/marklogic-60-released.html" title="MarkLogic 6.0 Released" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2012/09/marklogic-60-released.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-8668702388175038817</id><published>2012-08-30T07:37:00.001-06:00</published><updated>2014-05-25T07:31:22.150-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="fn:current-dateTime" /><category scheme="http://www.blogger.com/atom/ns#" term="fn:doc-available" /><category scheme="http://www.blogger.com/atom/ns#" term="fn:generate-id" /><category scheme="http://www.blogger.com/atom/ns#" term="unique ids" /><category scheme="http://www.blogger.com/atom/ns#" term="xdmp:request" /><category scheme="http://www.blogger.com/atom/ns#" term="xdmp:sha1" /><title type="text">Generate unique IDs for the collision paranoid</title><content type="html">There were posts recently to the MarkLogic Mailing List about avoiding collisions of ids in your database. The focus of the posts were about checking for items with the same id in the database. My argument is that rather than use something collision apt as xdmp:random, generate something more unique.&lt;br /&gt;&lt;br /&gt;So I came up with the following using xdmp:request, fn:current-dateTime, and fn:generate-id concatenated and passed to xdmp:sha1. This provides uniqueness based off of, a request, a moment in time, and a node in memory.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="3528304" id="gist-3528304" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Unique ID Generation"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xdmp:sha1(&lt;br /&gt;fn:concat(&lt;br /&gt;(: Unique per request :)&lt;br /&gt;xdmp:request(),&lt;br /&gt;(: Unique per moment in time :)&lt;br /&gt;fn:current-dateTime(),&lt;br /&gt;(: Unique per node in memory :)&lt;br /&gt;fn:generate-id(text {()})&lt;br /&gt;)&lt;br /&gt;)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;If you feel that it is still necessary, you can use fn:doc-available to determine whether or not a document at that location (if that is how your database works) exists already or not. I think you will find a collision very unlikely however, with 16^40 different possible ids.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/zxFimj-JIqw" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/8668702388175038817/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2012/08/generate-unique-ids-for-collision.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/8668702388175038817" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/8668702388175038817" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/zxFimj-JIqw/generate-unique-ids-for-collision.html" title="Generate unique IDs for the collision paranoid" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2012/08/generate-unique-ids-for-collision.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-7428998524216886361</id><published>2012-08-28T07:06:00.000-06:00</published><updated>2014-05-25T07:29:26.650-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="library module" /><category scheme="http://www.blogger.com/atom/ns#" term="static checking" /><category scheme="http://www.blogger.com/atom/ns#" term="xdmp:eval" /><title type="text">Static checking a library module</title><content type="html">I was very excited to come across the static check option for xdmp:eval. I immediately envisioned a firstline of defense against bad code reaching your code base. I was equally disappointed to see the following error when I tried it on library module: XDMP-EVALLIBMOD. I understand why you wouldn't be able to actually evaluate a library module, but there should be no reason you couldn't static check it.&lt;br /&gt;&lt;br /&gt;I didn't let that stop me. It is really simple to change a library module to a main module for the purpose of static checking. Here are the differences between a main module and a library module:&lt;br /&gt;&lt;br /&gt;1. The main module doesn't have a module declaration. http://www.w3.org/TR/xquery-30/#id-module-declaration&lt;br /&gt;2. The functions of a main module must be in the local namespace.&lt;br /&gt;3. The main module has a query body beyond the prolog.&lt;br /&gt;&lt;br /&gt;With a little fancy footwork we can make use of fn:concat and fn:replace to convert a library module to a main module for the sake of static checking.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="3497803" id="gist-3497803" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Static Checking a Library Module with xdmp:eval"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xdmp:eval(&lt;br /&gt;(: if module declaration exists change it to a main module:)&lt;br /&gt;if (fn:matches($module,'(^|[&amp;#10;&amp;#13;])\s*module\s+namespace\s+.+?=.*?;'))&lt;br /&gt;then &lt;br /&gt;(: retrieve namespace name for module :)&lt;br /&gt;let $namespace :=  fn:replace($module,'.*(^|[&amp;#10;&amp;#13;])\s*module\s+namespace\s+([^\s=]+)\s*=.*','$2','s'),&lt;br /&gt;(: check module to see if a default function namespace declaration already exists :)&lt;br /&gt;$has-default-namespace := fn:matches($module, '(declare\s+default\s+function\s+namespace\s+["''])([^"''])*(["''])')&lt;br /&gt;return&lt;br /&gt;(: add empty sequence for query body :)&lt;br /&gt;fn:concat(&lt;br /&gt;(: change function calles to local namespace :)&lt;br /&gt;fn:replace(&lt;br /&gt;(: change function declarations to local namespace :)&lt;br /&gt;fn:replace(&lt;br /&gt;(: change module  namespace declaration to just a namespace declaration :)&lt;br /&gt;fn:replace(&lt;br /&gt;$module,&lt;br /&gt;'(^|[&amp;#10;&amp;#13;])\s*module\s+(namespace\s+.+?=.*?;)',&lt;br /&gt;(: if a default function namespace declaration doesn't already exist set it to the local namespace :)&lt;br /&gt;fn:concat('$1 declare $2', if (fn:not($has-default-namespace)) then '&amp;#10; declare default function namespace "http://www.w3.org/2005/xquery-local-functions";' else ())&lt;br /&gt;),&lt;br /&gt;'(^|[&amp;#10;&amp;#13;])\s*declare[\s&amp;#10;&amp;#13;]+function[\s&amp;#10;&amp;#13;]+([^\s&amp;#10;&amp;#13;][^:\(]+:)?([^:][^\(]+\()',&lt;br /&gt;'$1declare function local:$3'&lt;br /&gt;),&lt;br /&gt;fn:concat('(^|\s)(',$namespace,':)'),&lt;br /&gt;if ($has-default-namespace)  then '$1local:' else ''&lt;br /&gt;),&lt;br /&gt;' ()'&lt;br /&gt;)&lt;br /&gt;else $module,&lt;br /&gt;(),&lt;br /&gt;&amp;lt;options xmlns="xdmp:eval"&amp;gt;&amp;lt;static-check&amp;gt;true&amp;lt;/static-check&amp;gt;&amp;lt;/options&amp;gt;)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistBlogger.js" type="text/javascript"&gt;&lt;/script&gt; &lt;br /&gt;&lt;script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt; &lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/MBP3-0rRwa4" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/7428998524216886361/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2012/08/static-checking-library-module.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/7428998524216886361" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/7428998524216886361" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/MBP3-0rRwa4/static-checking-library-module.html" title="Static checking a library module" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2012/08/static-checking-library-module.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-4700397402952484310</id><published>2012-08-15T07:54:00.001-06:00</published><updated>2013-01-01T20:37:22.065-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="empty" /><category scheme="http://www.blogger.com/atom/ns#" term="empty-sequence" /><category scheme="http://www.blogger.com/atom/ns#" term="exists" /><category scheme="http://www.blogger.com/atom/ns#" term="instance of" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic" /><category scheme="http://www.blogger.com/atom/ns#" term="prof:value" /><category scheme="http://www.blogger.com/atom/ns#" term="typeswitch" /><category scheme="http://www.blogger.com/atom/ns#" term="xQuery" /><title type="text">The many ways to detect an empty sequence</title><content type="html">I was recently thinking about the different ways that an empty sequence could be detected in XQuery. There were 7 ways that came to my mind. I thought I would compare the different ways performance wise. Unfortunately/fortunately there was no drastic differences. Profiling on the various functions I wrote, the elapsed times shifted around enough between the functions enough that there was no clear benefit of using one over the other.&lt;br /&gt;&lt;br /&gt;Anyway, here is the code I ran in QConsole if you want to play around yourself (Best to have results returned as text in its current form.). Each of these functions just iterate over a set and returns exactly what was passed in. If anything, it is nice to know you have options and there are many ways things can be accomplished in XQuery. &lt;br /&gt;&lt;br /&gt;If you come up with other ways please feel free to share.&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="3360214" id="gist-3360214" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Detecting Empty Sequences in XQuery"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;xquery version "1.0-ml";&lt;br /&gt;&lt;br /&gt;declare namespace prof = "http://marklogic.com/xdmp/profile";&lt;br /&gt;&lt;br /&gt;declare variable $set as item()+ := (1 to 25);&lt;br /&gt;&lt;br /&gt;declare function local:empty($items as item()*) {&lt;br /&gt;  if(empty($items))&lt;br /&gt;  then ()&lt;br /&gt;  else ($items[1],local:empty(subsequence($items,2)))&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:exists($items as item()*) {&lt;br /&gt;  if(exists($items))&lt;br /&gt;  then ($items[1],local:exists(subsequence($items,2)))&lt;br /&gt;  else ()&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:typeswitch-empty($items as item()*) {&lt;br /&gt;  typeswitch($items)&lt;br /&gt;  case empty-sequence() return ()&lt;br /&gt;  default return ($items[1],local:typeswitch-empty(subsequence($items,2)))&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:typeswitch-exists($items as item()*) {&lt;br /&gt;  typeswitch($items)&lt;br /&gt;  case item()+ return ($items[1],local:typeswitch-exists(subsequence($items,2)))&lt;br /&gt;  default return ()&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:instance-of-empty($items as item()*) {&lt;br /&gt;  if ($items instance of empty-sequence())&lt;br /&gt;  then ()&lt;br /&gt;  else ($items[1],local:instance-of-empty(subsequence($items,2)))&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:instance-of-exists($items as item()*) {&lt;br /&gt;  if ($items instance of item()+) &lt;br /&gt;  then ($items[1],local:instance-of-exists(subsequence($items,2)))&lt;br /&gt;  else ()&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;declare function local:inferred-boolean($items as item()*) {&lt;br /&gt;  if ($items) &lt;br /&gt;  then ($items[1],local:inferred-boolean(subsequence($items,2)))&lt;br /&gt;  else ()&lt;br /&gt;};&lt;br /&gt;prof:enable(xdmp:request()),&lt;br /&gt;"local:empty",&lt;br /&gt;prof:value('for $i in (1 to 1000) return local:empty($set)')[1]/prof:metadata/prof:overall-elapsed/string(),&lt;br /&gt;"local:exists",&lt;br /&gt;prof:value('for $i in (1 to 1000) return local:exists($set)')[1]/prof:metadata/prof:overall-elapsed/string(),&lt;br /&gt;"local:typeswitch-empty",&lt;br /&gt;prof:value('for $i in (1 to 1000) return local:typeswitch-empty($set)')[1]/prof:metadata/prof:overall-elapsed/string(),&lt;br /&gt;"local:typeswitch-exists",&lt;br /&gt;prof:value('for $i in (1 to 1000) return local:typeswitch-exists($set)')[1]/prof:metadata/prof:overall-elapsed/string(),&lt;br /&gt;"local:instance-of-empty",&lt;br /&gt;prof:value('for $i in (1 to 1000) return local:instance-of-empty($set)')[1]/prof:metadata/prof:overall-elapsed/string(),&lt;br /&gt;"local:instance-of-exists",&lt;br /&gt;prof:value('for $i in (1 to 1000) return local:instance-of-exists($set)')[1]/prof:metadata/prof:overall-elapsed/string(),&lt;br /&gt;"local:inferred-boolean",&lt;br /&gt;prof:value('for $i in (1 to 1000) return local:inferred-boolean($set)')[1]/prof:metadata/prof:overall-elapsed/string()&lt;/div&gt;&lt;br /&gt;&lt;script src="https://raw.github.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/6JV8bNrdSW0" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/4700397402952484310/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2012/08/the-many-ways-to-detect-empty-sequence.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/4700397402952484310" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/4700397402952484310" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/6JV8bNrdSW0/the-many-ways-to-detect-empty-sequence.html" title="The many ways to detect an empty sequence" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>3</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2012/08/the-many-ways-to-detect-empty-sequence.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-7604112102413778067.post-4646817837749745166</id><published>2012-08-08T21:00:00.000-06:00</published><updated>2013-01-01T20:43:03.426-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="i18n" /><category scheme="http://www.blogger.com/atom/ns#" term="map:map" /><category scheme="http://www.blogger.com/atom/ns#" term="MarkLogic" /><category scheme="http://www.blogger.com/atom/ns#" term="performance" /><category scheme="http://www.blogger.com/atom/ns#" term="xdmp:get-server-field" /><category scheme="http://www.blogger.com/atom/ns#" term="xdmp:set-server-field" /><category scheme="http://www.blogger.com/atom/ns#" term="xQuery" /><title type="text">Performance Enhanced i18n Library for MarkLogic</title><content type="html">When creating an application, it is probably a good idea to think ahead to internationalization. This can be achieved with key/value pairs stored your MarkLogic database. MarkLogic is fast, but if the number of strings you use grows to be substantial enough, the cost of retrieving these strings from the database for each request can become expensive. This why I created a library for dealing with the i18n strings in a efficient way.&lt;br /&gt;&lt;br /&gt;The first step that I take for performance is to store the values in map:map xml in the database. This xml can be loaded into a map:map object which will give you great performance when looking for values based off of a key because it works much like a hash table look up (I imagine that is what is happening behind the scenes.). This can be substantially faster than just using a predicate to filter based off of an attribute value.&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="3300455" id="gist-3300455" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Load Map From XML For Resource Bundle"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;map:map(bundle($locale, $bundle,$query)/map:map)&lt;/div&gt;&lt;br /&gt;The second step is to retain that map loaded into memory for any other calls to obtain values from your i18n bundle. This way the first call to the bundle takes the brunt of the execution time, while lookups that follow are ready to go in memory.&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="3300482" id="gist-3300482" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Put Map Object in Server Field Map Object"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;map:map(bundle($locale, $bundle,$query)/map:map)[map:put($current-bundles,$base-key,.),fn:true()]&lt;/div&gt;&lt;br /&gt;The final step is to make use of server fields. Server fields are values that are shared between all requests to a server in your MarkLogic cluster. There is no reason that you should need to load your bundle with every request when there are no changes made to your i18n bundle. So I pull bundles from the database and store them into a server field only when changes have been made to the bundle. This increases performance by not only having the items already in memory and decreases memory usage by having one map:map object per bundle shared between requests instead of having a map:map object per bundle per request. In my implementation I use the uri lexicon and the MarkLogic last-modified property.&lt;br /&gt;&lt;br /&gt;&lt;div class="gistLoad" data-id="3300501" id="gist-3300501" xml:space="preserve" itemscope itemtype="http://schema.org/Code"&gt;&lt;meta itemprop="name" content="Load Resource Bundle into Server Field"/&gt;&lt;br /&gt;&lt;meta itemprop="sampleType" content="inline"/&gt;&lt;br /&gt;&lt;meta itemprop="programmingLanguage" content="XQuery"/&gt;&lt;br /&gt;(: This loads a bundle into memory. :)&lt;br /&gt;declare function load-bundle($locale as xs:string, $bundle as xs:string, $query as cts:query?) as map:map {&lt;br /&gt; (: Calculate the key for the bundle which changes with every update to the bundle :)&lt;br /&gt; let $base-key as xs:string := fn:concat('/resources','/',&lt;br /&gt;  (:As of MarkLogic 4.2 the result of cts:register is always the same, provided the same query. So in this case we can use it to generate a unique id :)&lt;br /&gt;  if (fn:exists($query)) &lt;br /&gt;  then fn:string(cts:register($query)) &lt;br /&gt;  else 'default',&lt;br /&gt;  '/',$locale,'/',$bundle)&lt;br /&gt; return &lt;br /&gt;  if (fn:exists(map:get($current-bundles,$base-key)))&lt;br /&gt;  then map:get($current-bundles,$base-key)&lt;br /&gt;  else&lt;br /&gt;&lt;br /&gt;   let $timestamp-key as xs:string := fn:concat($base-key,'/timestamp'),&lt;br /&gt;    $timestamp as xs:string := fn:string(xdmp:get-server-field($timestamp-key))&lt;br /&gt;   (: Try to retrieve bundle from memory. :)&lt;br /&gt;   return&lt;br /&gt;   (: If it exists in memory in a server field return it. :)&lt;br /&gt;   if (fn:exists($timestamp) and fn:exists(cts:uris((),('limit=1'), &lt;br /&gt;        cts:and-query((&lt;br /&gt;         cts:element-query(&lt;br /&gt;          xs:QName('i18n'),&lt;br /&gt;          cts:and-query((&lt;br /&gt;           cts:element-attribute-value-query(xs:QName('i18n'),xs:QName('locale'), $locale, 'exact'),&lt;br /&gt;           cts:element-attribute-value-query(xs:QName('i18n'),xs:QName('id'), $bundle, 'exact')           &lt;br /&gt;          ))&lt;br /&gt;         ),&lt;br /&gt;         $query, &lt;br /&gt;         cts:properties-query( &lt;br /&gt;          cts:element-value-query(xs:QName('prop:last-modified'),$timestamp,'exact')&lt;br /&gt;         )&lt;br /&gt;        ))&lt;br /&gt;      ))) &lt;br /&gt;   then xdmp:get-server-field($base-key)&lt;br /&gt;   (: Otherwise load it. :)&lt;br /&gt;      else (&lt;br /&gt;    xdmp:set-server-field($base-key,map:map(bundle($locale, $bundle,$query)[xdmp:set-server-field($timestamp-key,property::prop:last-modified)]/map:map))[map:put($current-bundles,$base-key,.),fn:true()]&lt;br /&gt;       )&lt;br /&gt;};&lt;/div&gt;&lt;br /&gt;Checkout the library on &lt;a href="https://github.com/ryanjdew/XQuery-i18n"&gt;GitHub&lt;/a&gt;. &lt;br /&gt;&lt;script src="https://raw.github.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"&gt;&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/tDYaS/~4/QFJPLTLMJ2g" height="1" width="1" alt=""/&gt;</content><link rel="replies" type="application/atom+xml" href="http://maxdewpoint.blogspot.com/feeds/4646817837749745166/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://maxdewpoint.blogspot.com/2012/08/performance-enhanced-i18n-library-for.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/4646817837749745166" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7604112102413778067/posts/default/4646817837749745166" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/tDYaS/~3/QFJPLTLMJ2g/performance-enhanced-i18n-library-for.html" title="Performance Enhanced i18n Library for MarkLogic" /><author><name>Ryan Dew</name><uri>https://plus.google.com/100505234114666959249</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-tSXPgL2t9pA/AAAAAAAAAAI/AAAAAAAACTQ/Ht64f0AUYyY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://maxdewpoint.blogspot.com/2012/08/performance-enhanced-i18n-library-for.html</feedburner:origLink></entry></feed>
