Robert Cemper · Jan 6, 2018 go to post

This was more a code correction exercise. 
Honestly I wouldn't have done it that way at all. But using %XML.TextReader instead.
It was just to late in the evening to do a pretty solution.
The next auditor may do it.
 

BTW. for Attributes it'S %lev+1*3

Robert Cemper · Jan 5, 2018 go to post

pls. point me to that WSDL or post it so we can try.
Without WSDL all to say isthe same  what the error says: some important parameters are missing.

The XML document is well formed but the document is not valid

Robert Cemper · Jan 5, 2018 go to post

As Eduard already pointed out there is just no need to use %XML.Node as %XML.Document inherits it already

I have elaborated your code also to cover Attributes and Chlidren in the document.
and added some readability features.

To some extend  %XML.TextReader could have done the same.

No need to copy the code from browser the class + test data is attached. xmlreading.zip  

Class XML.J [ Abstract ]
{
ClassMethod GetXMLDocFromFile(file = "C:\InterSystems\Cache\mgr\user\Test.xml") As %XML.Document
{
    set reader=##class(%XML.Reader).%New()
    set status=reader.OpenFile(file)
    if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF}
#dim document as %XML.Document
    set document=reader.Document
 #; set reNo=##class(%XML.Node).%New() //check here
 #; set reNo.Document=document //check here
 #; do ..ShowNode(reNo)
    do ..ShowNamespaces(document)
#dim node as %XML.Node
    set %lev=0
    set node=document.GetDocumentElement()
    do ..Analyze(node)
    quit document
}
ClassMethod Analyze(node As %XML.Node)
{
    set hasChild =..ShowNode(node)
    set attribute=node.FirstAttributeName()
    while attribute'="" {
            do ..ShowAttribute(.attribute,node)
        }
    if hasChild {
        set tSC=node.MoveToFirstChild(1)
        if tSC , $i(%lev) {
            while tSC {
                do ..Analyze(node)
                set tSC=node.MoveToNextSibling(1)
                }
            do node.MoveToParent() if $i(%lev,-1)
            }
    }
    quit
}
ClassMethod ShowAttribute(ByRef attribute, node As %XML.Node)
{
   write !?(%lev+1*3),"Attribute_Name ",attribute
        ,!?(%lev+1*3),"Atribute_Value ",node.GetAttributeValue(attribute)
#; more to be added here
        ,!?(%lev+1*3),"--------------------------"
    set attribute=node.NextAttributeName(attribute)
    quit
}
ClassMethod ShowNamespaces(doc As %XML.Document)
{
    Set count=doc.CountNamespace()
    Write !, "Number of namespaces in document: "_count
    For i=1:1:count {
        Write !, "Namespace "_i_" is "_doc.GetNamespace(i)
}
}
// how to use the below method
ClassMethod ShowNode(node As %XML.Node) As %Boolean
{
    If node.NodeType=$$$xmlELEMENTNODE  {
        Write !?(%lev*3),"LocalName="_node.LocalName
#; Write !,"Namespace="_node.Namespace
#; }
#; If node.NodeType=$$$xmlELEMENTNODE {
#; Write !,"NamespaceIndex="_node.NamespaceIndex
        Write !?(%lev*3),"Nil="_node.Nil
        Write !?(%lev*3),"NodeData="_node.NodeData
        Write !?(%lev*3),"QName="_node.QName
    }
    Write !?(%lev*3),"NodeId="_node.NodeId
    Write !?(%lev*3),"NodeType="_node.NodeType
    Write !?(%lev*3),"HasChildNodes returns "_node.HasChildNodes()
    
    If node.NodeType=$$$xmlELEMENTNODE {
        Write !?(%lev*3),"GetNumberAttributes returns "_node.GetNumberAttributes()
        Set status=node.GetText(.text)
          If status {
           Write !?(%lev*3), "Text of the node is "_$tr(text,$c(10))
            else {
                Write !?(%lev*3), "GetText does not return text"
            }
    }
    quit node.HasChildNodes()
}
}
Robert Cemper · Jan 5, 2018 go to post

It seems to me you try to call a SOAP service.
That service requires some special XML structured content. That is missing. It is typically  placed in  Authtoken.Entity
you can test your request by

 set tSc = AuthToken.Post("/webservices/Void",1) to see what you send.with is empty in your case.

It may work with pure %Net.HttpReqquest but if you have a valid WSDL definition you better use
the WebService Client Generator in Caché Studio that does it all for you. 

It would be useful to have sour WSDL to try it. Pls. attach it.
As I don't have a personal account on UPS I'n unable to identify what you a re trying to achieve.

I worked also with PHP WS. It does a lot under cover (without your control) that you have to do in Caché by your own code.
eg. at any request the related WDSL is downloaded for actual mapping.

Robert Cemper · Jan 5, 2018 go to post

you should ensure that in the last else branch in method ..OutputNode() your variable

alChild  is an object of type %XML.Document to satify your method

.. XmlToJSONnode(sbJSON As %AbstractStream, node As %XML.Document, showNodeName As %Boolean) 
when you call it.

Robert Cemper · Jan 4, 2018 go to post

it just works with local variables in memory.

I referred to this:

USER>s ^rcc=sbJSON
USER>s x=^rcc
USER>zw x
x="6@%Stream.FileCharacter"
 
USER>d x.%New()
D x.%New()
^
<INVALID OREF>
USER>
Robert Cemper · Jan 4, 2018 go to post

I was wondering where this goes and how you could get so far.
Caché uses a temp file.
 

USER>set sbJSON =##class(%Stream.FileCharacter).%New()
USER>s sc=sbJSON.WriteLine(12123)
 
USER>zw sc
sc=1
 
USER>zw sbJSON
sbJSON=<OBJECT REFERENCE>[6@%Stream.FileCharacter]
+----------------- general information ---------------
|      oref value: 6
|      class name: %Stream.FileCharacter
| reference count: 2
+----------------- attribute values ------------------
|     (%Concurrency) = 1
|          %Location = ""  <Set>
|         (%LockRef) = ""
|          (%Locked) = 0
|              AtEnd = 0
|                BOM = ""
|         (CurrFile) = "C:\InterSystems\17E20\mgr\Temp\mAiLCZXuPXOaSQ.stream"
|                 Id = ""  <Set>
|     LineTerminator = $c(13,10)  <Set>
|      (MakePermLoc) = 1
|             (Mode) = 3
|(NormalizedDirectory) = "C:\InterSystems\17E20\mgr\Temp\"
|(OidTranslateTable) = 0
|         (ReadMode) = 0
|           ReadSize = ""
|      RemoveOnClose = 0
|        (StoreFile) = ""
|  StreamFormatWrite = 1
|         (TempFile) = "mAiLCZXuPXOaSQ.stream"
|     TranslateTable = ""  <Set>
|      UseVMSVersion = 0
|   (VariableRecord) = 0
+--------------- calculated references ---------------
|  CanonicalFilename   <Get>
|           Filename   <Get,Set>
|       LastModified   <Get>
|               Size   <Get>
+-----------------------------------------------------
 
USER>
Robert Cemper · Jan 4, 2018 go to post

I 'm not aware of such option.
I ran also the original class (with .$toJSOMFormat) in 2016.4  with the same effect.
JSON output (trapped over I/O redirection) looks also good.
I fear the huge XDATA block (HTML, JS, CSS) didn't make it correctly via the Studio import.
It looked very strange with many empty lines inserted. 

Robert Cemper · Jan 4, 2018 go to post

Analyzing you code I see the problem in this line:

              do sbJSON.WriteLine($C(92)_..SafeJSON(node.GetDocumentNode())_$C(92)_$C(58))


I take for given that sbJSON is a valid object.
So I further investigate on node 

   ..XmlToJSONnode( )  is called twice + recursive
#1  from ..
XmlToJSON() looks fine

#2 is suspicious as in  .. OutputNode() I see   
 

Method OutputNode(childname As %String, alChild As %RegisteredObject, sbJSON As %Stream, showNodeName As %Boolean)
{
             if (alChild = null)      // EMPTY, NOT AN OBJECT
            ... }
            elseif (alChild)          // IT IS eventually an OBJECT REFERENCE
            { ...  }
            else       // NOT EMPTY, NOT NUMERIC, AND NOT AN OBJECT REFERENCE
            {
               do ..XmlToJSONnode(sbJSON,alChild, showNodeName)
; > > > > > > > > > > > > > > > > > > > >^^^^^^  // WHAT is this now ???

            }
             do sbJSON.WriteLine($C(4))
}

so what you hand over is not an oref as this looks like <integer>@<classname>  
therefore you fail with <INVALID OREF>zXmlToJSONnode+3^SharpJSONToXML.1

so some action is required to find out what happens

BTW:

passing sbJSON by reference would make this recursive construct easier to understand
as you intend to work to the same stream object anyhow.
or just use %sbJSON as single common reference

Robert Cemper · Jan 4, 2018 go to post

with 

set tSc AuthToken.Post("/webservices/Void")

you miss some content to POST and get

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header/>
    <soapenv:Body>
        <soapenv:Fault>
            <faultcode>Client</faultcode>
            <faultstring>An exception has been raised as a result of client data.</faultstring>
            <detail>
                <err:Errors xmlns:err="http://www.ups.com/schema/xpci/1.0/error">
                    <err:ErrorDetail>
                        <err:Severity>Hard</err:Severity>
                        <err:PrimaryErrorCode>
                            <err:Code>10001</err:Code>
                            <err:Description>The XML document is not well formed</err:Description>
                            <err:Digest>Unexpected element: CDATA</err:Digest>
                        </err:PrimaryErrorCode>
                        <err:Location/>
                    </err:ErrorDetail>
                </err:Errors>
            </detail>
        </soapenv:Fault>
    </soapenv:Body>
</soapenv:Envelope>

use instead

set tSc AuthToken.Get("/webservices/Void")

and receive

<HTML>
<HEAD><TITLE>UPS Online Tools VoidWS</TITLE></HEAD>
<BODY><H2>
Service Name: VoidWS<br>
Remote User: null<br>
Server Port: 443<br>
Server Name: wwwcie.ups.com<br>
Servlet Path: /Void<br>
</H2>
</BODY></HTML>
Robert Cemper · Jan 4, 2018 go to post

The return value of your WebService has to be  of type
 ServiceTestPrd.Request.ReqPatInfo 

Method GetPatInfo(QueryInfo As %Stream.GlobalCharacter) As ServiceTestPrd.Request.ReqPatInfo  [ WebMethod ]

and you terminate with your object.

quit reqObj 
Robert Cemper · Jan 3, 2018 go to post

Update: 

Blocks.Router uses $toJSONFormat() {CR/LF formatedOutput }
this hidden function hasn't been ported. replacement with %ToJSON()  does it as well.
So TREE view works nice.

Map view gets no content (and no colored dots  crying ).
Reason:  Block Count=0 and also %Fill -> nothing to display (makes sense somehow). 
This is also with the original classes in 2016.1.4 ;
Looks like an privilege issue.

Robert Cemper · Jan 3, 2018 go to post

You still may be confronted with encoding issues:  8 bit vs. UniCode
and the correct sort order ASCII, French, 3 variants of German, ......many more

But your original installation knows this all.
 

Robert Cemper · Jan 3, 2018 go to post

You are missing the point.

12345 is the port used by the cache DB server   (default=1972) of your instance.
internally there is a mapping between the logical NAMESPACE and the physical disk directory and that NAMESPACE is used in connection string.
if your namespace is called DB then  you have to use 

jdbc:Cache://localhost:12345/DB

But if you just have the directory .../cache/db/cache.dat  you can't say what NAMESPACE this is
You have to know your Caché configuration.

Some reading on Caché configuration may give you background information
http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…

Robert Cemper · Jan 3, 2018 go to post

do you plan an update for changes to JSON syntax   
- .%To... instead of .$to...  and so on
- local Caché variables and expressions in parenthesis. (  var )

I tried and it finally compiled.  Could run the page just never saw a result.  

Robert Cemper · Jan 2, 2018 go to post

OK. I understand.
- I doubt if a Linux distribution of Caché contains any Windows mechanics. ( to be checked with WRC )
- on the other hand I don't believe it's possible or make sense  to run Caché Win distribution in a Win-Shell ...
So suggested workaround:
Have a VM (or small machine) with Windows +Caché and connect via ECP or similar (REST, WebService, JDBC, ...)  to your main Caché instance on Linux. 

OR:

Wrap some C# around your DLL on a Windows box and present it as a WebService that you call from Linux.

Robert Cemper · Jan 2, 2018 go to post

??? For what reason would you expect to have MicroSoft .NET on Linux/Unix systems ???

Robert Cemper · Jan 2, 2018 go to post

Where does Array go to proxyObject ?
I'm missing something like: Set Body.Array=Array

Robert Cemper · Dec 31, 2017 go to post

I would like to share your wishes to all participants with special emphasis on uninterrupted HEALTH.
 

Robert Cemper · Dec 30, 2017 go to post

Hi Jeffrey,

Your descriptions matches pretty well what is titled in Ensemble as "Workflow"
http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…

It uses specialized Request and Response messages that are designed to allow a significant time gap in between.
It's originally designed for human interactions but to my understanding it implements exactly your "sideline".
And human interaction is just there to show it may take long time to get a reply.
There is also an example in ENSDEMO  Demo.Workflow.Production  ​

 HTH,

Robert

Robert Cemper · Dec 29, 2017 go to post

Not clear what you mean with "login page".
for the MgmtPoatal you connect to a HTTP port (default=57772) with a CSP PAGE and and and ...

With JDBC you connect to the object service port (default = 1972)  + namespace  

The IP address is of course the same. Here 127.0.0.1  or localhost 

Robert Cemper · Dec 29, 2017 go to post

Check MAXLEN for Property CSFAELIGVENCITY wherever that was defined.
 

As MAXLENis not checked for data output you may want to use a SQLcomputed property
that limits output to 20.

eg. {set {*}=$Extract(CSFAELIGVENCITY,1,20) }

Robert Cemper · Dec 28, 2017 go to post

So you didn't run the full installation.
You need to update you installation and add the libraries.
Or run a  2nd installtion in parallel 

Robert Cemper · Dec 28, 2017 go to post

Pls. move this request away from "Community Feedback " to Group "Caché"  to make it public visible.
I just found it by accident. 

it is in you Caché installation 
%CACHEROOT%\dev\java\lib\JDK17\...

%CACHEROOT%\dev\java\lib\JDK18\...

whatever you may need