Create a Hash Table using webMethods documents

Hello,

I am implementing a logic where I would want to store all the elements of a document or xmlString into HasMap. The key to the hashmap is the xpath of the variable and the value to the hashmap would be the actual value of the variable. For Example, suppose I have an XML of the below form:

<?xml version="1.0"?>
<header>
         <H1> h1</H1>
         <H2> h2</H2>
         <H3> h3</H3>
         <body>
                   <B1> B1</B1>
                   <B2> B2</B2>
                   <body1>
                                <B3> B3 </B3> 
                                 <B4> B4 </B4>
                                 <body2>
                                               <B5> B5 </B5>
                                 </body2>
                                 <body2>
                                               <B6> B6 </B6>
                                 </body2>
                   </body1  >
          </body>
</header>

My Hashmap should look like

Key                                                         Value
header.H1                                                H1
header.H2                                                H2
header.H3                                                H3
header.body.B1                                        B1
header.body.B2                                        B2
header.body.body1.B3                             B3
header.body.body1.B4                             B4
header.body.body1.body2[0].B5              B5 
header.body.body1.body2[1].B6              B6 

If there are multiple instances, as in document list or string list, the instance of that list should be available in the hashmap. Please could anyone guide me how we can achieve this using webMethods flow service or a java service.

Many thanks in Advance.

–R Chikkanna

review the services under: pub.hashtable, see if they will serve your needs.

Hi,

I have gone through all the methods in the public folder, nothing serves my purpose. Creating a hash table and inserting values into it is a pretty simple job, however, getting the keys and values is the challenge here. If there is any way of getting xpath of each field inside the document, i believe I will be able to crack this.

Hard-coding won’t help as the document size and structure varies every time…!! I need to find a way where I can traverse through whole document, get xpath of each element in the document which I can use to get the values.

Thanks

Hi Roopa,

can you check for the PSUtilities package available from the Community download section?

Eventually this one contains some helpful services.

Regards,
Holger

Hello Holger,

Thank you for your response. I will download the package and check if this helps me resolve the problem in hand.

Thanks,
Roopa

Hello,

I couldn’t find any service that would serve my purpose in PSUtilities that I downloaded from the community forum(20120912092616517_000_PSUtilities2_4, dated Feb 27, 2015). I must agree that there are many interesting services in the package like compress and decompress, getNestedRecord, concatField etc., which will be of help in my current project. Thanks for suggesting this.

I am planning to convert the document into an xml and find out the xpath using a java service(xml parser). I will let you know if this works.

Thanks,
Roopa

Roopa,

I have a simple question: why?

If the key of your hashtable is basically going to be an XPath- or XQuery-like string, why not just keep the object in memory as an XML node instead of a HashMap? Then, if you want to pull something out of the object using that query string, you simply call queryXMLNode.

Percio

Hi Percio,

I tried using the getXMLNodeIterator, getNextXMLNode and queryXMLNode in sequence, by not specifying the criteria for the node iterator. I got the header tags successfully, however, when there are nested documents and document lists, I was unable to get the child tag information. The result was a document again.

Now, I want to check if the result of getNextXMLNode is a document or a basic tag. If the Node returned is a document, I will have to loop over it again and query the child tags. This is something that I am working on in parallel to writing a java service.

Thanks,
Roopa

Roopa,

I’m not sure I made myself clear. Instead of having a static variable that holds a HashMap, simply have a static variable that holds the XML node. Then, when you want to get a specific element from the node using XQL, for example, you simply retrieve the node from the static variable and pass it to queryXMLNode along with the query string. No need to parse the XML ahead of time, no need for a HashMap.

I created a quick sample for you. Take a look at the attached package and look at the ‘test’ service. It shows how you can call the other services to set the static variable and then how to query that variable.

Hope this helps,
Percio
PcStaticXmlNode.zip (12.9 KB)

Hi Percio,

Thank you for taking out time to create the sample service. This service works for a simple XML like the one I have specified in the question. However, in real time, the actual xml is huge and the number of nodes within the document list varies(Ex: header.body.body1.body2), in which case Hardcoding doesn’t work. The query value for the service queryXmlNode has to be picked up dynamically.

I am attaching a couple of the real time example XML’s for your reference. These are my input XMLs. The schema in both the XML’s is same but size varies. In this case, I have to parse the xml. I am planning to map the values to the output document and then parse the XML to generate a key value pair for further processing.

Thanks,
Roopa

shipCancel2.txt (45.8 KB)
shipcancel1.txt (14.7 KB)

I hard-coded the query for demonstration purposes, but of course, it doesn’t have to be hard-coded.

I don’t think I fully understand your use case or why you want to do what you want to do. You say you want to “generate a key value pair for further processing” but why? Why do you feel you have to flatten the XML to process it? What’s so special about your processing that requires a flat, key/value pair structure?

Having said all this, I hope you realize that because you’re dealing with a hierarchical structure, if you want to flatten the XML in a generic way, you will likely need recursion. Recursion is possible in Flow but it requires some careful attention, plus performance will not be the greatest. You may then want to consider writing your code in Java anyway, at which point, there are several libraries that you can make use of to achieve what you’re trying to do. If you Google for how to convert an XML into a hashmap in Java, you should find several hits. My question remains though: why?

Good luck,
Percio

1 Like
public static final void getKeyValuePairs(IData pipeline)
		throws ServiceException {
	// pipeline
	IDataCursor pipelineCursor = pipeline.getCursor();
	IData docData = IDataUtil.getIData(pipelineCursor,"doc") ;
	
	getKeyVals(docData.getCursor(),"",true);
	String[] keys = KeyVals.keySet().toArray(new String[0]);
	String[] value = KeyVals.values().toArray(new String[0]);
	String[][]	KeyValuePairs =new String [KeyVals.size()][2];
	for (int i = 0; i < KeyVals.size(); i++)
	{	KeyValuePairs[i][0]=keys[i];
		KeyValuePairs[i][1]=value[i];
	}
	IDataUtil.put( pipelineCursor, "KeyValuePairs", KeyValuePairs );
	pipelineCursor.destroy();
	
		
}

// --- <<IS-BEGIN-SHARED-SOURCE-AREA>> ---

public static final void getKeyVals(IDataCursor _cursor,String keyName,boolean root){
	_cursor.first();
	String key;
	while (_cursor.hasMoreData())
	{
	Object value = IDataUtil.get(_cursor,_cursor.getKey());
	if (value instanceof IData)
	{
		
		IDataCursor childDataCursor=((IData)value).getCursor();
		if(keyName=="")
		getKeyVals(childDataCursor,_cursor.getKey(),false);
		else
		getKeyVals(childDataCursor,keyName+"."+_cursor.getKey(),false);
		JournalLogger.log(4,90,4,"***************found an IData-"+_cursor.getKey()+ "And the iteration is "+i);
	}
	else if(value instanceof IData[]){
		JournalLogger.log(4,90,4,"***************found an List-"+_cursor.getKey()+ "And the iteration is "+i);
		JournalLogger.log(4,90,4,"***************Child Data Cursor created-"+_cursor.getKey()+ "And the iteration is "+i);
		IData[]	indocs = IDataUtil.getIDataArray(_cursor,_cursor.getKey());
		JournalLogger.log(4,90,4,"***************Indocs Created-"+_cursor.getKey()+ "And the iteration is "+i);
		IDataCursor tempcursor;
		for(int j=0;j<indocs.length;j++)
		{
			tempcursor=	indocs[j].getCursor();		
			if(keyName=="")
				getKeyVals(tempcursor,_cursor.getKey()+"."+j,false);
				else
				getKeyVals(tempcursor,keyName+"."+_cursor.getKey()+"."+j,false);
			
		}
	}
	else
	{
		if (!root)
			key =keyName+"."+_cursor.getKey();
		else
				key=_cursor.getKey();
		KeyVals.put(key, IDataUtil.getString(_cursor,_cursor.getKey()));
		JournalLogger.log(4,90,4,"KeyValuepair Logged :-"+key +IDataUtil.getString(_cursor,_cursor.getKey())+ "And the iteration is "+i);
		i++;
	}
	_cursor.next();
	
	
	}
	_cursor.last();
	Object value = IDataUtil.get(_cursor,_cursor.getKey());
	if (value instanceof IData)
	{
		IDataCursor childDataCursor=((IData)value).getCursor();
		if(keyName=="")
		getKeyVals(childDataCursor,_cursor.getKey(),false);
		else
			getKeyVals(childDataCursor,keyName+"."+_cursor.getKey(),false);
	}
	else if(value instanceof IData[]){
		JournalLogger.log(4,90,4,"***************found an List-"+_cursor.getKey()+ "And the iteration is "+i);
		IData[]	indocs = IDataUtil.getIDataArray(_cursor,_cursor.getKey());
		JournalLogger.log(4,90,4,"***************Indocs Created-"+_cursor.getKey()+ "And the iteration is "+i);
		IDataCursor tempcursor;
		for(int j=0;j<indocs.length;j++)
		{
			tempcursor=	indocs[j].getCursor();		
			if(keyName=="")
				getKeyVals(tempcursor,_cursor.getKey()+"."+j,false);
				else
				getKeyVals(tempcursor,keyName+"."+_cursor.getKey()+"."+j,false);
			
		}
	}
	else
	{
		if (!root)
			key =keyName+"."+_cursor.getKey();
		else
			key=_cursor.getKey();
		KeyVals.put(key, IDataUtil.getString(_cursor,_cursor.getKey()));
		i++;
	}
	
}

public static int i = 0;
public static LinkedHashMap<String,String> KeyVals=new LinkedHashMap<>();