How to use %XML.Node

I have read here  and tried to use the supplied examples to see what they do but keep on getting error please advice:

Method GetXMLDocFromFile(file = "C:test2.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}
    set document=reader.Document
    set reNo=##class(%XML.Node).%New()//check here
    set reNo.Document=document//check here
    do ..ShowNamespaces(document)
    do ..ShowNode(reNo)//check here
    quit document
}
Method 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




Method ShowNode(node As %XML.Node)
{
    Write !,"LocalName="_node.LocalName
    If node.NodeType=$$$xmlELEMENTNODE  {
        Write !,"Namespace="_node.Namespace
    }
    If node.NodeType=$$$xmlELEMENTNODE {
        Write !,"NamespaceIndex="_node.NamespaceIndex
     }
    Write !,"Nil="_node.Nil
    Write !,"NodeData="_node.NodeData
    Write !,"NodeId="_node.NodeId
    Write !,"NodeType="_node.NodeType
    Write !,"QName="_node.QName
    Write !,"HasChildNodes returns "_node.HasChildNodes()
    Write !,"GetNumberAttributes returns "_node.GetNumberAttributes()
    Set status=node.GetText(.text)
    If status {
        Write !, "Text of the node is "_text
        } else {
            Write !, "GetText does not return text"
        }
}
  

the error I am getting is as follows:<UNDEFINED>zGetXMLDocFromFile+5^XMLToDyna.3 *reNo.If you check where I highlighted in red I have defined reNo so where am I going wrong

Answers

Try to remove reNo altogether and get the root node from the xml document:

do ..ShowNode(document.GetDocumentElement())

In GetDocumentElement method, you can see that for node to exist it needs 2 things:

  • Document
  • Pointer to the exact node

When you created the node manually,  you've done the first but not the second.

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()
}
}

 

I'd move

Write !?(%lev*3)

into a separate method:

ClassMethod Log(text)
{
  Write !?(%lev*3), text
}

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

Comments

Use static classmethods, unless you need them to be instance methods.