Search code examples
javascriptxpathmarklogic

Error in running Xpath in MarkLogic Data Hub Harmonization header plugin


I am trying to use XPath in the MarkLogic Data Hub header. The goal is to get a Property2 element value from an XML document (content) (see sample below)

<instance>
<info xmlns="">
   <title>Entity</title>
   <version>0.0.1</version>
 </info>
<Entity xmlns="">
    <Property1>100533</Property1>
    <Property2>130008HU46</Property2>
    <Property3>Z1-Electrico</Property3>
</Entity>

Below is the code for the header plugin in my harmonization flow:

	'use strict'
	/*
	* Create Headers Plugin
	*
	* @param id       - the identifier returned by the collector
	* @param content  - the output of your content plugin
	* @param options  - an object containing options. Options are sent from Java
	*
	* @return - an object of headers
	*/
	var he = require("/lib/hierarchyEditLib.sjs");
	var hd = require("/lib/headerLib.sjs");

	function createHeaders(id, content, options) {

	let ctx = createContext(content);  
	let guid = hd.generateUUID()

	return {
		"guid": guid,
		"sourceURI": id,
		"context" : ctx
		   }
	}

	function createContext(content)
	{
	let header = {};
  
	header.BusinessUnit = content.xpath('//*:' + "Property2" + '/string()').toString();

	header.DateOfHarmonization =  fn.replace(fn.substring(fn.string(fn.currentDateTime()),1,10), "-", "/");
	header.TimeOfHarmonization = fn.string(fn.currentTime());
   
	return header;  
	}

	module.exports = {
	createHeaders: createHeaders
	};

Everytime I run the flow, I am always seeing an error below in the traces:

JS-JAVASCRIPT: header.BusinessUnit = content.xpath('//*:' + "Property2" + '/string()').toString(); -- Error running JavaScript request: TypeError: content.xpath is not a function

Is there any reference I'm missing or is there something wrong / insufficient in my current logic?


Solution

  • Which version of DHF is this for? If it's 2.x then there's a bit of translation going on in the backend that is actually passing things as objects and maps in the background. 3.0 handles things more natively, and this translation doesn't occur.

    So when you are running this, you're actually translating the xml document into a map:map in the background, then passing that value back into the javascript engine (V8) which interprets it as a type Object (a sequence of key:values, which the mirror in xquery to the map).

    So, you can resolve this a few ways: one of the ways would be to simply fn.head(content) and then dot-notion identify properties off it:

    let contentObj = fn.head(content);
    header.BusinessUnit = contentObj.Property2;
    

    This should return what you're expecting. If you need to dynamically swap what the property will be, contentObj['Property2'] should also work for you.

    We've identified this is intuitive when working with javascript and xml in DHF, so in the next release, we will be moving to treating all documents (whether xml or json) as Nodes in server-side javascript. This means they will be passed as ObjectNode, so you can do dot-notion OR xpath against them raw out of the box.