I see 5 options :

  • any classmethod can be projected as SQL Procedure. So using your ODBC adapter you may communicate that way with Caché
    based on rather poor personal experience of PHP & ODBC it is definitely not my favorite.
  • With Angular & PHP you are in the Web environment. So SOAP Webservices may be useful.
    I had a very positive experience with that approach. see it here  Feeling the power of Caché
  • Actually I would rather use REST in combination with JSON
  • If rather synchronous interaction between both sides is required AJAX (+JSON) could be a way 
  • Or for longer lasting asynchronous communication WebSockets might be appropriate.

So you have a choice what fits best to your needs.

BTW.

zwrite @reader.GlobalName

USER>zwrite @reader.GlobalName
^||CacheTemp=5
^||CacheTemp(5,1)=$lb("element","","Oceano","Oceano",0,1)
^||CacheTemp(5,2)=$lb("element","","Header","Header",0,2)
^||CacheTemp(5,3)=$lb("element","","DataSource","DataSource",0,3)
^||CacheTemp(5,4)=$lb("chars","Oceano","")
^||CacheTemp(5,5)=$lb("endelement","","DataSource","DataSource")
^||CacheTemp(5,6)=$lb("element","","DataType","DataType",0,3)
^||CacheTemp(5,7)=$lb("chars","EDAttendance","")
^||CacheTemp(5,8)=$lb("endelement","","DataType","DataType")
^||CacheTemp(5,9)=$lb("endelement","","Header","Header")
^||CacheTemp(5,10)=$lb("element","","Body","Body",0,2)
^||CacheTemp(5,11)=$lb("element","","MIU","MIU",0,3)
^||CacheTemp(5,12)=$lb("element","","Department","Department",0,4)
^||CacheTemp(5,13)=$lb("chars","BCH","")
^||CacheTemp(5,14)=$lb("endelement","","Department","Department")
^||CacheTemp(5,15)=$lb("element","","TotalNumber","TotalNumber",0,4)
^||CacheTemp(5,16)=$lb("chars","6","")
^||CacheTemp(5,17)=$lb("endelement","","TotalNumber","TotalNumber")
^||CacheTemp(5,18)=$lb("element","","NumberWaitingToBeSeen","NumberWaitingToBeSeen",0,4)
^||CacheTemp(5,19)=$lb("endelement","","NumberWaitingToBeSeen","NumberWaitingToBeSeen")
^||CacheTemp(5,20)=$lb("element","","LongestWaitMin","LongestWaitMin",0,4)
^||CacheTemp(5,21)=$lb("endelement","","LongestWaitMin","LongestWaitMin")
^||CacheTemp(5,22)=$lb("endelement","","MIU","MIU")
^||CacheTemp(5,23)=$lb("element","","MIU","MIU",0,3)
^||CacheTemp(5,24)=$lb("element","","Department","Department",0,4)
^||CacheTemp(5,25)=$lb("chars","BOS","")
^||CacheTemp(5,26)=$lb("endelement","","Department","Department")
^||CacheTemp(5,27)=$lb("element","","TotalNumber","TotalNumber",0,4)
^||CacheTemp(5,28)=$lb("chars","1","")
^||CacheTemp(5,29)=$lb("endelement","","TotalNumber","TotalNumber")
^||CacheTemp(5,30)=$lb("element","","NumberWaitingToBeSeen","NumberWaitingToBeSeen",0,4)
^||CacheTemp(5,31)=$lb("chars","1","")
^||CacheTemp(5,32)=$lb("endelement","","NumberWaitingToBeSeen","NumberWaitingToBeSeen")
^||CacheTemp(5,33)=$lb("element","","LongestWaitMin","LongestWaitMin",0,4)
^||CacheTemp(5,34)=$lb("chars","109293","")
^||CacheTemp(5,35)=$lb("endelement","","LongestWaitMin","LongestWaitMin")
^||CacheTemp(5,36)=$lb("endelement","","MIU","MIU")
^||CacheTemp(5,37)=$lb("endelement","","Body","Body")
^||CacheTemp(5,38)=$lb("endelement","","Oceano","Oceano")

structure is OK, and it worked for me.

Removing all CR,LF,TAB,BLANK still looks good here. 
Could you have some control  characters in your string ?

USER>ZZDUMP myfile may show it

USER>write $TR(myfile,$c(13,10,9,32))
<Oceano><Header><DataSource>Oceano</DataSource><DataType>EDAttendance</DataType></Header><Body><MIU><Department>BCH</Department><TotalNumber>6</TotalNumber><NumberWaitingToBeSeen/><LongestWaitMin/></MIU><MIU><Department>BOS</Department><TotalNumber>1</TotalNumber><NumberWaitingToBeSeen>1</NumberWaitingToBeSeen><LongestWaitMin>109293</LongestWaitMin></MIU></Body></Oceano>

By XML bit I understand you have some myfile="<mynode>anytext</mynode>" or similar in hands

so this should cover your needs:

USER>set sc=##class(%XML.TextReader).ParseString(myfile,.reader)
USER>zwrite @reader.GlobalName
^||CacheTemp=1
^||CacheTemp(1,1)=$lb("element","","mynode","mynode",0,1)
^||CacheTemp(1,2)=$lb("chars","anytext","")
^||CacheTemp(1,3)=$lb("endelement","","mynode","mynode")

or is the content of myfile something else ?? 

First, CACHETEMP doesn't maintain a Journal. (could be a minor advantage) .

Second, CACHETEMP follows a different storage strategy as it is kept in memory (global buffers) as long as affordable.
While for the other DBs data (global buffer blocks) get written to disk as soon as possible it is the opposite for CACHETEMP.

Third, CACHETEMP is common to all namespaces.

Forth, CACHETEMP is cleared at every restart and total empty after.
 I doubt that this could be useful in an ECP setup. 

to my understanding, there is no technical limit.
Though I believe to remember that it used to be ~16.000 some time in past.

Class SYS.Database maps to ^SYS("CONFIG","IRIS","Databases",<DBNAME>) and has NO  limit there

similar Namespaces are stored in SYS("CONFIG","IRIS","Namespaces",<NSPCE>) an are covered by %SYS.Namespace

If there is any limit it must be related to internal memory structures.  (gmheap ??)

Out of curiosity, I have built a  more exotic solution that is easier to understand. (At least for me)
I don't like so much this protocol upgrade stuff and encrypting and simulation of a browser.

My personal workaround:

  • start browser over ZF(-1, "start chrome http://.................my csp......")
  • the page gets my request passed with the URL. very simple just as a Hash
  • the page does all the WS stuff via JavaScript
  • the reply is returned using Hyperevent #call(....) 

It works fine and is rather "classic CSP" style.