web stats
Assigning Arbitrary Empty XML Node - Mirth Community

Go Back   Mirth Community > Mirth Connect > Support

Reply
 
Thread Tools Display Modes
  #1  
Old 04-18-2019, 08:07 AM
ace ace is offline
Mirth Newb
 
Join Date: May 2016
Location: Austin, TX, USA
Posts: 9
ace is on a distinguished road
Default Assigning Arbitrary Empty XML Node

Is it possible to create an arbitrary empty/blank XML node to assign to the arrays that Connect uses to represent HL7?

For example, I can hardcode a statement like this which replaces the MSH:

var msgXML = new XML(SerializerFactory.getSerializer('HL7V2').toXML (inStr));
msgXML['PID']['PID.5'] = <PID.5/>;

But, the <PID.5/> seems like it is a special variable or constant in Connect, not a String, so is there a way to have a variable that contains the
name of an HL7 field, like the String, 'MSH.10', or in the case above, 'PID.5', and by using that String variable, dynamically assign
an empty node, as I have done in the hardcoded version? Perhaps something like this:

var hl7FieldName = 'PID.5';
var emptyXmlNode = magicMysteryFunction(hl7FieldName);
msgXML['PID']['PID.5'] = emptyXmlNode;
Reply With Quote
  #2  
Old 04-18-2019, 09:16 AM
agermano agermano is offline
Mirth Guru
 
Join Date: Apr 2017
Location: Indiana, USA
Posts: 894
agermano is on a distinguished road
Default

You can do it with e4x templating like this:
Code:
var hl7FieldName = 'PID.5';
msgXML['PID'][hl7FieldName] = <{hl7FieldName}/>;
The magical mystery function is a mirth helper function called createSegment.
Code:
var hl7FieldName = 'PID.5';
var emptyXmlNode = createSegment(hl7FieldName);
msgXML['PID']['PID.5'] = emptyXmlNode;
You can add the parent object and it will insert it for you, but this will only replace the first occurrence if the field or segment is repeating. The previous two examples will replace a repeating PID.5 field with a single empty occurence.
Code:
var hl7FieldName = 'PID.5';
var emptyXmlNode = createSegment(hl7FieldName, msgXML['PID']);
And if you know that msgXML['PID']['PID.5'] refers to a single node that already exists in the message, you can do this to empty it. It will complain that setChildren isn't a function if msgXML['PID']['PID.5'] doesn't exist or returns multiple nodes.
Code:
msgXML['PID']['PID.5'].setChildren(new XMLList());
Reply With Quote
  #3  
Old 04-30-2019, 02:18 PM
ace ace is offline
Mirth Newb
 
Join Date: May 2016
Location: Austin, TX, USA
Posts: 9
ace is on a distinguished road
Default Assigning Arbitrary Empty XML Node

Thanks for the ideas, agermano. I am just getting back to this.

This approach is the most useful for me. My previous report that it did not work was the result of a bad test. User error. / My Bad.:

var msgXML = new XML(SerializerFactory.getSerializer('HL7V2').toXML (connectorMessage.getRawData().toString()));
var segment = 'PID';
var hl7FieldName = 'PID.7';
msgXML[segment][hl7FieldName] = <{hl7FieldName}/>;
var neutralizedMessage = SerializerFactory.getSerializer('HL7V2').fromXML(m sgXML.toString());//THE SPACE BETWEEN m AND s IS ACTUALLY NOT THERE!!!


But for replacing an arbitrarily deep field, all but the 3rd one, require me to access the Array of Arrays with hard-coded depths of reference, for example, where msgXML[segName][fieldName] is 2 levels deep. Since I want to write a function that can take an arbitrary field or subfield name, I can imagine parsing the field name and using the 3rd approach to build a copy of the msgXML Array, one field at a time, in a series of loops, and then convert that edited copy back to XML, but that seems clunky, and probably slow-performing, so I was hoping there was a way to build a string that could be used as a path into the array (or into the XML) that could be used as an index for the edit.

Last edited by ace; 05-02-2019 at 07:18 AM. Reason: Removing bad test results. :-P
Reply With Quote
  #4  
Old 05-10-2019, 08:59 AM
agermano agermano is offline
Mirth Guru
 
Join Date: Apr 2017
Location: Indiana, USA
Posts: 894
agermano is on a distinguished road
Default

Each approach has different benefits and drawbacks. You might have to use multiple approaches in a generalized function depending on initial state and desired outcome.

For example, what do you do when a parent, or more critically a segment, doesn't exist? By default new segments will be created at the end of the message. What do you do when existing segments are repeating? Are the repeating segments consecutive? What do you do when existing fields are repeating?

If you have a very strict outcome in mind, you may want to build a new message (using the outbound template) from pieces of the inbound message rather than trying to delete everything you don't need.
Reply With Quote
  #5  
Old 05-17-2019, 09:17 AM
ace ace is offline
Mirth Newb
 
Join Date: May 2016
Location: Austin, TX, USA
Posts: 9
ace is on a distinguished road
Default Assigning Arbitrary Empty XML Node

That is a good point. In my case, I just want to know that there is no data in the node my function is told to blank-out.

So, if there are child nodes, it is fine to clobber them. And, if there is a missing parent, that implies there is no data in the subject node, so in that case, there is no change to make on the XML.
Reply With Quote
  #6  
Old 09-05-2019, 09:32 AM
ace ace is offline
Mirth Newb
 
Join Date: May 2016
Location: Austin, TX, USA
Posts: 9
ace is on a distinguished road
Default Assigning Arbitrary Empty XML Node

My solution ended up being to use loops to build up a command string that contains the Array representation of my XML on the left side of an assignment statement and the empty-node representation on the right side, like this:

var msgXML = new XML(SerializerFactory.getSerializer('HL7V2').toXML (hl7Str));
// actual logic to assign stringToEvaluate is much more complicated
stringToEvaluate = "msgXML['MSH']['MSH.7'] = <MSH.7/>";
eval(stringToEvaluate);
return SerializerFactory.getSerializer('HL7V2').fromXML(m sgXML.toString());


I think this will also work on subfields with a command string like:
xml['PID']['PID.5']['PID.5.2'] = </PID.5.2>;

Be careful when using this technique, that you want to clobber all repetitions of the field to which you are assigning the empty-node (and everything else out to leaf nodes). Even if you want to preserve some repetitions of a field, calling eval() on a concatenated string may still be a good approach to building up an arbitrary statement for manipulating Connect's Array-representation of the XML node.
Reply With Quote
  #7  
Old 09-11-2019, 12:34 AM
Charleskic Charleskic is offline
What's HL7?
 
Join Date: Jul 2019
Location: United States
Posts: 1
Charleskic is on a distinguished road
Send a message via ICQ to Charleskic Send a message via AIM to Charleskic Send a message via Yahoo to Charleskic Send a message via Skype™ to Charleskic
Default Assigning Arbitrary Empty XML Node

Hi - I am trying to create an XML message with a repeating segment that has many loops in it. I would like to keep the loops for those segments together in the XML output. When I am using the appendChild, it is creating it at the end of the message. I am pulling the data from a database to an XML message.

Here is my xml template:
<specimenInformation>
<tumorSpecimenInformation>
</tumorSpecimenInformation>
</specimenInformation>
<tests>
<testName></testName>
<testCode></testCode>
<platformTechnology></platformTechnology>
<testMethodology></testMethodology>
<testResults></testResults>
</tests>
<clinicalTrials>
<nctID></nctID>
<titleBrief></titleBrief>
</clinicalTrials>
<therapies>
<therapyName></therapyName>
</therapies>
</root>

Here is part of my code:
I pull from a query
if resultTest.getStringTest_Id == holdTestId

// do nothing


else

createSegmenttests, tmp, testCount;
//createSegmentAftertests, tmpspecimenInformation, testCount;

testCountD = testCount 1;

// test info
tmpteststestCounttestName = validateresultTest.getStringTest, ;
tmpteststestCounttestCode = validateresultTest.getStringCompendium_Id, ;
tmpteststestCountplatformTechnology = validateresultTest.getStringTechnology, ;
tmpteststestCounttestMethodology = validateresultTest.getStringMethod, ;

testCountResults = testCount;
testCount;
resultIndex = 1;
resultCount = 0;



based on test, I have a switch setup to send over different type of results
switchStringresultTest.getStringTechnology

case NGS:
var resultStr = <testResults/>;

tmpteststestCountResults.appendChildresultStr;

break;

case CNA:
var resultStr = <testResults/>;

tmpteststestCountResults.appendChildresultStr;

break;

then I have a new query for the therapies and clinical trials:
var caseDrugs = executeCachedQuerydbConn, caseDrugQuery;

caseDrugsCount = 0;

while caseDrugs.next
tmptherapiestherapyNamecaseDrugsCount = caseDrugs.getStringDrugs;
caseDrugsCount;


and
var caseCTCs = executeCachedQuerydbConn, ctcQuery;

ctcCount = 0;

while caseCTCs.next
tmpclinicalTrialsnctIDctcCount = caseCTCs.getStringNCT_ID;
tmpclinicalTrialstitleBriefctcCount = caseCTCs.getStringBRIEF_TITLE;
ctcCount;


The output of the xml looks like this:
<specimenInformation>
data here
</specimenInformation>
<tests>
<testName></testName>
<testCode></testCode>
<platformTechnology></platformTechnology>
<testMethodology></testMethodology>
<testResults>
1 test result here
</testResults>
</tests>
<clinicalTrials> then case clinical trials</clinicalTrials>
<therapies>
<therapyName/>case therapies <therapyName/>
</therapies>
<tests>
<testName></testName>
<testCode></testCode>
<platformTechnology></platformTechnology>
<testMethodology></testMethodology>
<testResults>
then the other tests and test results start
</testResults>
</tests>


I would like the other test results to appear before the clincial trials and therapies for the case.
Reply With Quote
Reply

Tags
empty, variable, xml

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -8. The time now is 03:17 PM.


Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Mirth Corporation