Brendan Batchelder · Jan 25, 2017 go to post

The reason this is happening is because your message specifies UTF-8 in MSH:18.  If you remove that from your test message, it will look correct.

When using the 'test' button to test a DTL, it will always try to use the encoding defined in MSH:18 to read the message.

When using a business service to read the message, it will try to use the encoding defined in MSH:18 if it is defined.  If it is not defined, then the 'Default Char Encoding' setting determines which encoding will be used.  You can force the 'Default Char Encoding' to override MSH:18 by putting a ! before it.

http://docs.intersystems.com/ens20161/csp/docbook/DocBook.UI.Page.cls?K…

Brendan Batchelder · Dec 22, 2016 go to post

I just tested this in latest and it worked fine for me.  Here is the Message Structure Raw Definition I used:

2.3.1:MSH~{~[~2.3.1:PID~[~{~2.3.1:NK1~}~]~[~2.3.1:PV1~[~2.3.1:PV2~]~]~]~{~[~2.3.1:ORC~]~2.3.1:OBR~[~{~2.3.1:NTE~}~]~CommunityTest:TQS~[~{~[~{~2.3.1:OBX~}~]~[~{~2.3.1:NTE~}~]~}~]~}~}

Here is a screenshot showing the visual representation of the Message Structure:

I created a sample message by modifying a sample ORU_R01 I had and I opened it in the Interoperate message viewer using these settings (my Schema is named CommunityTest and my DocType is named TEST):

When I view the file and mouse over the final NTE segment, here is the VDoc path I'm given.  You can see that it's in the OBXgrp:

What version are you on?  I think you should open a WRC problem to investigate this further.  You can call the WRC at 617-621-0700 or you can email support@intersystems.com

Brendan Batchelder · Dec 15, 2016 go to post

On top of that, for the field portion of the VDoc path, using a numeric reference will always work, even if the segment structure of the message doesn't match the schema.

In order to see how to reference the field by name rather than numeric, the best tool to use is the Interoperate message viewer.  This can be found in the management portal at Ensemble->Interoperate->HL7 v2.x->HL7 Message Viewer.

If you save your message as a file and open it using this message viewer, and set the DocType correctly, then you will see the message on the right side with all segment identifiers and fields highlighted in blue.  You can mouse over any segment identifier to see the exact segment path needed to reach that segment, and then you can mouse over any field to see the name that should be used to reference that field.

Here are some examples.  First is the settings I used to open the message, followed by the tooltip when I mouse over the OBX segment, followed by the tooltip when I mouse over the '39' field.

There is a known problem with our documentation, scheduled to be fixed in 2017.1.

The class documentation for %Net.SSH.Session states: "Once connected and authenticated, the SSH object can be used to perform SCP (Secure Copy) operations of single files to and from the remote system".

This is not true.  There is no way to use %Net.SSH.Session to do a secure copy.

The example at this URL in the documentation shows how to create a REST business service which retrieves JSON data, converts it to a proxy object, and then extracts values from the proxy object to store in a response:

http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…

Assuming you are retrieving your JSON data from a REST service, your use case is similar.  Instead of storing the values in a response, you would want to create a new request class to hold the values.  Replace pResponse in the example with an instance of your new request class, fill it with data from the JSON proxy object, then send it to a message router component with ..SendRequestAsync.

Then, in your message router, you can add a DTL which transforms your new request class into an ADT_A31 HL7 message.

<PROPERTY DOES NOT EXIST> means your code is trying to reference a class property that does not exist.  The rest of the error message should tell you which property you tried to reference that didn't exist.

After you added those 3 properties to the WeatherResponse class, did you save and compile it?

If you're not able to resolve this, can you post the complete error message?  What property is it telling you doesn't exist?

Brendan Batchelder · Oct 26, 2016 go to post

If you just want to know whether there is a value or not in element1.element2.element3, compare it to "".  The 'not equal' ('=) operator in Cache contains an apostrophe, so it must be escaped in the XML. (if a '= b write "a is not equal to b")

<if condition='source.{element1.element2.element3}&apos;=""'>

This will return True if element1.element2.element3 has a value, or it will return False if either element1.element2.element3 does not exist or if element1.element2.element3 exists but contains no value, like this:

<element3></element3>

If you need to differentiate between these two cases, things get more difficult.  There is no method in XML VDoc that can tell you whether an element exists or not.  In general with XML, the existence of an element shouldn't be used as a logical boolean value.  Instead you should use a boolean datatype in your XML schema.

If you must check whether element3 exists or not, you could do it like this:

say your XML document looks like this:

<element1><element2><element3>sometext</element3></element2></element1>

If you were to get the value of element2 with an assign action like this:

<assign value='element1.element2' property='e2' action='set' />

then after that line, the variable e2 will hold the value "<element3>sometext</element3>" so to check for the existence of element3, you could search e2 for the text "<element3>" with the ..Contains function:

<if condition='..Contains(e2,"&lt;element3&gt;")' >

If your element3 might be self-closed (like this: <element3 />) then you'll need to account for that possibility as well.

Brendan Batchelder · Sep 27, 2016 go to post

I am seeing the same thing.  OutputToString() internally uses OutputToIOStream() but it sets the CharEncoding on the stream to "binary" before passing it.  I think this is the source of the problem.

I was able to work around it using OutputToLibraryStream instead:

ENSEMBLE>set msg = ##class(EnsLib.EDI.XML.Document).ImportFromString("<Test>מִבְחָן</Test>")

ENSEMBLE>write msg.OutputToString()
<Test>???????</Test>
ENSEMBLE>set stream = ##class(%Stream.TmpCharacter).%New()

ENSEMBLE>write msg.OutputToLibraryStream(.stream)
1
ENSEMBLE>write stream.Read()
<Test>מִבְחָן</Test>
Brendan Batchelder · Aug 24, 2016 go to post

Just to add on to this, lookup tables are stored in ^Ens.LookupTable, subscripted by the table name and then the key.  The value of each node is the lookup value of the key in the subscript.

For example, if you have a table named Codes which contains a key named 123 that maps to value "ABC", it will look like this in the global:

^Ens.LookupTable("Codes",123)="ABC"

The reason reverse lookups are not supported is because we allow many keys to map to the same value.  So if you need to find a key, given a value, there may be many values that match.

Writing code to perform a reverse lookup will involve copying the ^Ens.LookupTable global into a variable subscripted by value rather than by key, like this:

ReverseLookupTable("Codes","ABC")=123

and then performing a lookup on that variable.

Brendan Batchelder · Aug 24, 2016 go to post

Hi Nupur,

I think solving this problem will take some investigation.  I recommend opening a WRC problem.

-Brendan

Brendan Batchelder · Aug 11, 2016 go to post

The testing form isn't smart enough to handle array or list properties.  The easiest way I've found to test these is to create a  file business service and add code to populate the array with some hard-coded values.  Then add that service to your production, set the file path, and copy any random file into the file path directory to trigger the service.  Here's an example file service to do this:

Class Community.TestArray Extends Ens.BusinessService
{
  Parameter ADAPTER = "EnsLib.File.InboundAdapter";
  Method OnProcessInput(pInput As %Stream.Object, Output pOutput As %RegisteredObject) As %Status
  {
    set tTestMsg = ##class(MyApp.MyRequest).%New()
    do tTestMsg.idToTokenArray.Insert("One")
    do tTestMsg.idToTokenArray.Insert("Two")
    do tTestMsg.idToTokenArray.Insert("Three")
    quit ..SendRequestAsync("OperationToTest",tTestMsg)
  }
}
 

Brendan Batchelder · Jul 25, 2016 go to post

Make sure the 'Enable Standard Requests' setting on the REST business service is checked, Port is blank, and Pool Size is set to 0.  This will ensure the business service only listens for requests through the CSP Gateway and not through its own port.  Be sure to construct the URL for accessing the REST service as described in the documentation here, under "Defining the URL Using UrlMap and EnsServicePrefix":

http://docs.intersystems.com/ens20161/csp/docbook/DocBook.UI.Page.cls?K…

Brendan Batchelder · Jul 19, 2016 go to post

I see $$$TRACE statements in your code, which leads me to believe you are using Ensemble.

What you're trying to do is much easier with EnsLib.EDI.XML.Document, and there are adapters supporting the use of this message class.

Here's an example:

ENSEMBLE>set msg = ##class(EnsLib.EDI.XML.Document).ImportFromString(tData)
ENSEMBLE>w msg.GetValueAt("/")
<HHSOS><DIAGNOSES><DIAGNOSIS_DATA><DIAGNOSIS_DATA_GUID>3762875</DIAGNOSIS_DATA_GUID><DIAGNOSIS_DATA_GUID>37628752</DIAGNOSIS_DATA_GUID></DIAGNOSIS_DATA><DIAGNOSIS_DATA/><DIAGNOSIS_DATA/><DIAGNOSIS_DATA_GUID>37628753</DIAGNOSIS_DATA_GUID></DIAGNOSES></HHSOS>
ENSEMBLE>w msg.GetValueAt("/HHSOS/DIAGNOSES")
<DIAGNOSIS_DATA><DIAGNOSIS_DATA_GUID>3762875</DIAGNOSIS_DATA_GUID><DIAGNOSIS_DATA_GUID>37628752</DIAGNOSIS_DATA_GUID></DIAGNOSIS_DATA><DIAGNOSIS_DATA/><DIAGNOSIS_DATA/><DIAGNOSIS_DATA_GUID>37628753</DIAGNOSIS_DATA_GUID>
ENSEMBLE>w msg.GetValueAt("/HHSOS/DIAGNOSES/DIAGNOSIS_DATA[*]")
3
ENSEMBLE>w msg.GetValueAt("/HHSOS/DIAGNOSES/DIAGNOSIS_DATA[1]")
<DIAGNOSIS_DATA_GUID>3762875</DIAGNOSIS_DATA_GUID><DIAGNOSIS_DATA_GUID>37628752</DIAGNOSIS_DATA_GUID>
ENSEMBLE>w msg.GetValueAt("/HHSOS/DIAGNOSES/DIAGNOSIS_DATA[2]")
ENSEMBLE>w msg.GetValueAt("/HHSOS/DIAGNOSES/DIAGNOSIS_DATA[1]/DIAGNOSIS_DATA_GUID[*]")
2
ENSEMBLE>w msg.GetValueAt("/HHSOS/DIAGNOSES/DIAGNOSIS_DATA[1]/DIAGNOSIS_DATA_GUID[1]")
3762875
ENSEMBLE>w msg.GetValueAt("/HHSOS/DIAGNOSES/DIAGNOSIS_DATA[1]/DIAGNOSIS_DATA_GUID[2]")
37628752
 

These are called DOM-style paths as opposed to VDoc paths.  Here's the documentation:

http://docs.intersystems.com/ens20161/csp/docbook/DocBook.UI.Page.cls?K…;

Brendan Batchelder · Jul 19, 2016 go to post

If you use Managed Alerts, there is a custom FunctionSet function IsRecentManagedAlert() which you can use to suppress repeated alerts.  Here's an excerpt from the documentation:

The rule can check whether the alert is a repeat occurrence of a previous alert that is represented by a currently open managed alert. To do this, the rule uses the Ens.Alerting.Rule.FunctionSet.IsRecentManagedAlert() function. The IsRecentManagedAlert() function tests if there is a recent open managed alert that is from the same component and has the same text as the specified alert. You can optionally specify that the function adds a reoccurs action to the existing managed alert.

http://docs.intersystems.com/ens20161/csp/docbook/DocBook.UI.Page.cls?K…