C# to Cache objects

I am trying to achieve this in cache objects I am using  2014.1 here is the original code in C# and would like to convert this to cache

here is my code first c# and cache follows

     class Program
    {
        /// <summary>
        /// This function loads a XML document from the specified string.
        /// </summary>
        /// <param name="xml">Input XML string</param>
        /// <returns>XML to Json converted string</returns>
        public static string XmlToJSON(string xml)
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xml);
            
            StringBuilder sbJSON = new StringBuilder();
            sbJSON.Append("{ ");
            XmlToJSONnode(sbJSON, xmlDoc.DocumentElement, true);
            sbJSON.Append("}");
            return sbJSON.ToString();
        }
        
        /// <summary>
        /// Output a XmlElement, possibly as part of a higher array
        /// </summary>
        /// <param name="sbJSON">Json string to be created</param>
        /// <param name="node">XML node name</param>
        /// <param name="showNodeName">ArrayList of string or XmlElement</param>
        private static void XmlToJSONnode(StringBuilder sbJSON, XmlElement node, 
                                            bool showNodeName)
        {
            if (showNodeName)
            {
                sbJSON.Append("\"" + SafeJSON(node.Name) + "\": ");
            }
            sbJSON.Append("{");
 
            // Building a sorted list of key-value pairs where key is case-sensitive
            // nodeName value is an ArrayList of string or XmlElement so that we know
            // whether the nodeName is an array or not.
            SortedList<string, object> childNodeNames = new SortedList<string, object>();
 
            // Add in all node attributes.
            if (node.Attributes != null)
            {
                foreach (XmlAttribute attr in node.Attributes)
                    StoreChildNode(childNodeNames, attr.Name, attr.InnerText);
            }
 
            // Add in all nodes.
            foreach (XmlNode cnode in node.ChildNodes)
            {
                if (cnode is XmlText)
                {
                    StoreChildNode(childNodeNames, "value", cnode.InnerText);
                }
                else if (cnode is XmlElement)
                {
                    StoreChildNode(childNodeNames, cnode.Name, cnode);
                }
            }
 
            // Now output all stored info.
            foreach (string childname in childNodeNames.Keys)
            {
                List<object> alChild = (List<object>)childNodeNames[childname];
                if (alChild.Count == 1)
                    OutputNode(childname, alChild[0], sbJSON, true);
                else
                {
                    sbJSON.Append(" \"" + SafeJSON(childname) + "\": [ ");
                    foreach (object Child in alChild)
                        OutputNode(childname, Child, sbJSON, false);
                    sbJSON.Remove(sbJSON.Length - 2, 2);
                    sbJSON.Append(" ], ");
                }
            }
            sbJSON.Remove(sbJSON.Length - 2, 2);
            sbJSON.Append(" }");
        }
                
        /// <summary>
        /// Store data associated with each nodeName so that we know whether 
        /// the nodeName is an array or not.
        /// </summary>
        /// <param name="childNodeNames">Collection of child nodes</param>
        /// <param name="nodeName">XML node name</param>
        /// <param name="nodeValue">XML node value</param>
        private static void StoreChildNode(SortedList<string, object> childNodeNames, 
            string nodeName, object nodeValue)
        {
            // Pre-process contraction of XmlElements.
            if (nodeValue is XmlElement)
            {
                // Convert <aa></aa> into "aa":null
                // <aa>xx</aa> into "aa":"xx".
                XmlNode cnode = (XmlNode)nodeValue;
                if (cnode.Attributes.Count == 0)
                {
                    XmlNodeList children = cnode.ChildNodes;
                    if (children.Count == 0)
                    {
                        nodeValue = null;
                    }
                    else if (children.Count == 1 && (children[0] is XmlText))
                    {
                        nodeValue = ((XmlText)(children[0])).InnerText;
                    }
                }
            }
            // Add nodeValue to ArrayList associated with each nodeName.
            // If nodeName doesn't exist then add it.
            List<object> ValuesAL;
 
            if (childNodeNames.ContainsKey(nodeName))
            {
                ValuesAL = (List<object>)childNodeNames[nodeName];
            }
            else
            {
                ValuesAL = new List<object>();
                childNodeNames[nodeName] = ValuesAL;
            }
            ValuesAL.Add(nodeValue);
        }
 
        /// <summary>
        /// This functions outputs all the stored information inside a child node.
        /// </summary>
        /// <param name="childname">Chile node name</param>
        /// <param name="alChild">Child node</param>
        /// <param name="sbJSON">Json string</param>
        /// <param name="showNodeName">Node visibility</param>
        private static void OutputNode(string childname, object alChild, 
            StringBuilder sbJSON, bool showNodeName)
        {
            if (alChild == null)
            {
                if (showNodeName)
                {
                    sbJSON.Append("\"" + SafeJSON(childname) + "\": ");
                }
                sbJSON.Append("null");
            }
            else if (alChild is string)
            {
                if (showNodeName)
                {
                    sbJSON.Append("\"" + SafeJSON(childname) + "\": ");
                }
                string sChild = (string)alChild;
                sChild = sChild.Trim();
                sbJSON.Append("\"" + SafeJSON(sChild) + "\"");
            }
            else
            {
                XmlToJSONnode(sbJSON, (XmlElement)alChild, showNodeName);
            }
            sbJSON.Append(", ");
        }
        
        /// <summary>
        /// This function makes a string safe for JSON.
        /// </summary>
        /// <param name="sIn">Input child node</param>
        /// <returns>String safe Json</returns>
        private static string SafeJSON(string sIn)
        {
            StringBuilder sbOut = new StringBuilder(sIn.Length);
            foreach (char ch in sIn)
            {
                if (Char.IsControl(ch) || ch == '\'')
                {
                    int ich = (int)ch;
                    sbOut.Append(@"\u" + ich.ToString("x4"));
                    continue;
                }
                else if (ch == '\"' || ch == '\\' || ch == '/')
                {
                    sbOut.Append('\\');
                }
                sbOut.Append(ch);
            }
            return sbOut.ToString();
        }
 
        /// <summary>
        /// This function converts Json string to XML
        /// </summary>
        /// <param name="json">Inout Json string</param>
        /// <returns>Converted XML string</returns>
        public static XmlDocument JsonToXml(string json)
        {
            XmlNode newNode = null;
            XmlNode appendToNode = null;
            string[] arrElementData;
 
            XmlDocument returnXmlDoc = new XmlDocument();
            returnXmlDoc.LoadXml("<menu />");
            XmlNode rootNode = returnXmlDoc.SelectSingleNode("menu");
            appendToNode = rootNode;
            
            string[] arrElements = json.Split('\r');
            foreach (string element in arrElements)
            {
                string processElement = element.Replace("\r", "").Replace("\n", "").Replace("\t", "").Trim();
                if ((processElement.IndexOf("}") > -1 || processElement.IndexOf("]") > -1) &&
                    appendToNode != rootNode)
                {
                    appendToNode = appendToNode.ParentNode;
                }
                else if (processElement.IndexOf("[") > -1)
                {
                    processElement = processElement.Replace(":", "").Replace("[", "").Replace("\"", "").Trim();
                    newNode = returnXmlDoc.CreateElement(processElement);
                    appendToNode.AppendChild(newNode);
                    appendToNode = newNode;
                }
                else if (processElement.IndexOf("{") > -1 && processElement.IndexOf(":") > -1)
                {
                    processElement = processElement.Replace(":", "").Replace("{", "").Replace("\"", "").Trim();
                    newNode = returnXmlDoc.CreateElement(processElement);
                    appendToNode.AppendChild(newNode);
                    appendToNode = newNode;
                }
                else
                {
                    if (processElement.IndexOf(":") > -1)
                    {
                        arrElementData = processElement.Replace(": \"", ":").Replace("\",", "").Replace("\"", "").Split(':');
                        newNode = returnXmlDoc.CreateElement(arrElementData[0]);
                        for (int i = 1; i < arrElementData.Length; i++)
                        { newNode.InnerText += arrElementData[i]; }
                        appendToNode.AppendChild(newNode);
                    }
                }
            }
            return returnXmlDoc;
        }
 
        static void Main(string[] args)
        {
            string xml = "<menu id=\"file\" value=\"File\"> " +
                  "<popup>" +
                    "<menuitem value=\"New\" onclick=\"CreateNewDoc()\" />" +
                    "<menuitem value=\"Open\" onclick=\"OpenDoc()\" />" +
                    "<menuitem value=\"Close\" onclick=\"CloseDoc()\" />" +
                  "</popup>" +
                "</menu>";
            Console.WriteLine("Input XML string:\n");
            Console.WriteLine(xml);
            Console.WriteLine("\nOutput JSON string:\n");
            Console.WriteLine(XmlToJSON(xml)); 
            Console.WriteLine("\n================================================================================\n");
            
            const string json = @"{
                                ""foo"":""bar"",
                                ""complexFoo"": {
                                    ""subFoo"":""subBar""
                                    }
                                }";
            Console.WriteLine("Input JSON string:\n");
            Console.WriteLine(json);
            Console.WriteLine("\nOutput XML string:\n");
            Console.WriteLine(JsonToXml(json).InnerXml);
            Console.WriteLine();
        }
    }
Class SharpJSONToXML Extends %RegisteredObject
{
///<summary>
/// This functions loads a xml stream from a specified file
/// <param name="myfile">input xml file
Method LoadXMLFile(myfile As %String = "C:\test2.xml") As %Stream
{
  // open a text file using a %Library.File stream
  Set file = ##class(%File).%New(myfile)
  Do file.Open("RU") // same flags as the OPEN command
nbsp; // and copy the file into Memo
  Set incomeStream =##class(%Stream.FileCharacter).%New()
  Do incomeStream.CopyFrom(file)
nbsp; Set file = ""     // close the file
  Do ..XmlToJSON(incomeStream)
 return incomeStream
}
<summary>
/// This function loads a XML stream.
/// </summary>
/// <param name="xml">Input XML stream</param>
/// <returns>XML to Json converted stream</returns>
Method XmlToJSON(xml As %Stream) As %Stream
{
 
            set xmlDoc =##class(%XML.TextReader).ParseStream(xml,.textreader)
           
            set sbJSON =##class(%Stream.FileCharacter).%New()
            do sbJSON.WriteLine($C(123))
            do ..XmlToJSONnode(sbJSON,textreader.Name,1)
            do sbJSON.writeLine($C(125))
            return sbJSON
}
<summary>
/// Output a XmlElement, possibly as part of a higher array
/// </summary>
/// <param name="sbJSON">Json string to be created</param>
/// <param name="node">XML node name</param>
/// <param name="showNodeName">ArrayList of string or XmlElement</param>
Method XmlToJSONnode(sbJSON As %AbstractStream, node As %XML.Document, showNodeName As %Boolean)
{
 
            if (showNodeName)
            {
               do sbJSON.WriteLine($C(92)_..SafeJSON(node.GetDocumentNode())_$C(92)_$C(58))
            }
            do sbJSON.WriteLine($C(123))
 
            // Building a sorted list of key-value pairs where key is case-sensitive
            // nodeName value is an ArrayList of string or XmlElement so that we know
            // whether the nodeName is an array or not.
            Set childNodeNames =##class(%ListOfObjects).%New()
 
            // Add in all node attributes.
            For tI=1:1:node.Count()
         {
        Set tResult=node.GetAt(tI)
      
        if (tResult.HasAttributes)
               {
                    For tJ=1:1:tResult.AttributeCount
      {
       Do tResult.MoveToAttributeIndex(tJ)
       
       do ..StoreChildNode(childNodeNames, tResult.Name, tResult.Value)
      }
                }
                  // Add in all nodes.
                if tResult.HasChildNodes()
                {
                 if (tResult.Name){do ..StoreChildNode(childNodeNames,tResult.Name, tI) }elseif (tResult.Value){ do ..StoreChildNode(childNodeNames, "value",tResult.Value)}
             }
      }
          
            // Now output all stored info.
            for childname=1:1:childNodeNames
            {
               #dim alChild as %ListOfObjects
                if (alChild.Count = 1)
                {
                  do ..OutputNode(childname, alChild, sbJSON,1)
                }
                else
                {
                do sbJSON.WriteLine($C(92)_..SafeJSON(childname)_$C(92)_$C(58)_$C(91))
                
                    for tm=1:1: alChild
                    {
                        do ..OutputNode(childname, Child, sbJSON,0)
                   do sbJSON.Remove(sbJSON.Length - 2, 2)
                   do sbJSON.WriteLine($C(93)_$C(44))
                    }
                }
            }
           do sbJSON.Remove(sbJSON.Length - 2, 2)
           do sbJSON.WriteLine($C(125))
}
/// <summary>
/// Store data associated with each nodeName so that we know whether 
/// the nodeName is an array or not.
/// </summary>
/// <param name="childNodeNames">Collection of child nodes</param>
/// <param name="nodeName">XML node name</param>
/// <param name="nodeValue">XML node value</param>
Method StoreChildNode(childNodeNames As %ListOfObjects(CLASSNAME="%XML.XPATH.Result"), nodeName As %String, nodeValue As %XML.Node)
{
 
            // Pre-process contraction of XmlElements.
            if (nodeValue.NodeType="Element")
            {
                // Convert <aa></aa> into "aa":null
                // <aa>xx</aa> into "aa":"xx".
                #dim cnode As %XML.Node
                #dim children As %XML.Node 
               
                if (cnode.Attributes.Count = 0)
                {
                    set children = cnode.HasChildNodes()
                    if (children.Count = 0)
                    {
                       
                    }
                    elseif (children.Count = 1)
                    {
                        
                    }
                }
            }
            // Add nodeValue to ArrayList associated with each nodeName.
            // If nodeName doesn't exist then add it.
            #dim ValuesAL as %ListOfObjects
 
            if (childNodeNames.ContainsKey(nodeName))
            {
               set ValuesAL = childNodeNames
            }
            else
            {
               
               set childNodeNames = ValuesAL
            }
            set ValuesAL=$LISTBUILD(nodeValue)
}

/// <summary>
/// This functions outputs all the stored information inside a child node.
/// </summary>
/// <param name="childname">Chile node name</param>
/// <param name="alChild">Child node</param>
/// <param name="sbJSON">Json string</param>
/// <param name="showNodeName">Node visibility</param>
Method OutputNode(childname As %String, alChild As %RegisteredObject, sbJSON As %Stream, showNodeName As %Boolean)
{
 
            if (alChild = null)
            {
                if (showNodeName)
                {
                   do sbJSON.WriteLine($C(92)_..SafeJSON(childname)_$C(92)_$C(58))
                }
               do sbJSON.WriteLine("null")
            }
            elseif (alChild)
            {
                if (showNodeName)
                {
                    do sbJSON.WriteLine($C(92)_..SafeJSON(childname)_$C(92)_$C(58))
                }
                set sChild = alChild
               set sChild = TRIM("")
                do sbJSON.writeLine($C(92)_..SafeJSON(sChild)_$C(92))
            }
            else
            {
               do ..XmlToJSONnode(sbJSON,alChild, showNodeName)
            }
             do sbJSON.WriteLine($C(4))
/// <summary>
/// This function makes a string safe for JSON.
/// </summary>
/// <param name="sIn">Input child node</param>
/// <returns>String safe Json</returns>
Method SafeJSON(sIn As %XML.Node) As %Stream
{
 
            Set sbOut = ##class(%Stream.FileCharacter).%New()
            for i=1:1:sIn
            {
                if ($C(60) || $C(92)_$C(62))
                {
                   
                    continue
                }
                elseif ($C(92)_$C(34) || $C(92)_$C(92) || $C(47))
                {
                    do sbOut.write($C(92)_$C(92))
                }
               do sbOut.write()
            }
            return sbOut
}
}

Answers

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

 

 

passing sbJSON by reference would make this recursive construct easier to understand

Object are always passed by reference.

Comments

so far when I run my code in cache I get this error <INVALID OREF>zXmlToJSONnode+3^SharpJSONToXML.1 and I would like to know the equivalent in cache for that method if you look at it

@Robert.Cemper

sbJSON that actually get passed to XmlToJSONNode is not an object. Additionally try this modification to XmlToJSON (you need to specify file if you want to use file stream):

Method XmlToJSON(xml As %Stream) As %Stream
{
            set xmlDoc =##class(%XML.TextReader).ParseStream(xml,.textreader)          
            set sbJSON =##class(%Stream.FileCharacter).%New()
            do sbJSON.LinkToFile("somefile")
            do sbJSON.WriteLine($C(123))
            do ..XmlToJSONnode(sbJSON,textreader.Name,1)
            do sbJSON.writeLine($C(125))
            return sbJSON
}

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>

that's is the only way I could do it have any suggestion on how I can Improve that thank you

@Robert.Cemper

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.