Page 1 of 1

Replacement for MoveXMLNode()

Posted: Mon Dec 29, 2008 1:00 am
by StanDan
I was having trouble getting MoveXMLNode() to work (bug report here.) I did a search on the forum and found out that MoveXMLNode() had never been mentioned anywhere. So obviously it's not a wildly popular feature. :D

Anyway, here's my solution, in case anybody uses it and runs into the same problem I had.

It's not a perfect solutions since GetXMLNodeText() returns all the text within the given node, without regard to its position in relation to child nodes (i.e. in moving <p>This<b>will</b>not<b>work</b></p> to another location you will get <p><b>will</b><b>work</b>Thisnot</p>.) There's no easy way to get around this without resorting to the expat API, which is beyond me.

It's great for configuration files though, where you just need to maintain the DOM structure and nodes which contain data have only one child (the actual text.)

Code: Select all

Prototype.l ProtoMvXMLNode(*node, *par, *prv=0)
Prototype.l ProtoCpXMLNode(*node, *par, *prv=0)

Procedure.l XMLDeepCopy(*node, *dest)
  If *node = 0 Or *dest = 0
    ProcedureReturn 0
  EndIf
  nodeType = XMLNodeType(*node)
  If nodeType = #PB_XML_Normal Or nodeType = #PB_XML_Instruction
    nodeName.s = GetXMLNodeName(*node)
    If nodeType = #PB_XML_Instruction And nodeName <> ""
      SetXMLNodeName(*dest, nodeName)
    Else
      SetXMLNodeName(*dest, nodeName)
    EndIf
  EndIf
  If nodeType <> #PB_XML_Root
    nodeText.s = GetXMLNodeText(*node)
    SetXMLNodeText(*dest, nodeText)
  EndIf
  If nodeType = #PB_XML_Normal And ExamineXMLAttributes(*node)
    Repeat
      hasAttr = NextXMLAttribute(*node)
      If hasAttr <> 0
        attr.s = XMLAttributeName(*node)
        value.s = XMLAttributeValue(*node)
        SetXMLAttribute(*dest, attr, value)
      EndIf
    Until hasAttr = 0
  EndIf
  *child = ChildXMLNode(*node)
  If *child = 0
    ProcedureReturn 1
  EndIf
  
  NewList Nodes.l()

  ; Otherwise add the next children.
  Repeat
    AddElement(Nodes())
    Nodes() = *child
    *child = NextXMLNode(*child)
  Until *child = 0
  
  *new = 0
  *par = *dest
  *prv = 0
  ForEach Nodes()
    nodeType = XMLNodeType(Nodes())
    If nodeType = #PB_XML_Root
      ProcedureReturn 0
    EndIf
    If *prv = 0
      *new = CreateXMLNode(*par, 0, nodeType)
      If *new = 0
        ProcedureReturn 0
      EndIf
    Else
      *new = CreateXMLNode(*par, *prv, nodeType)
      If *new = 0
        ProcedureReturn 0
      EndIf
    EndIf
    If XMLDeepCopy(Nodes(), *new) = 0
      ProcedureReturn 0
    EndIf
    *prv = *new
  Next
  ProcedureReturn 1
EndProcedure

Procedure.l ProcCpXMLNode(*node, *par, *prv)
  If *par = 0 Or *node = 0
    ProcedureReturn 0
  EndIf
  *new = 0
  nodeType = XMLNodeType(*node)
  If nodeType = #PB_XML_Root
    ProcedureReturn 0
  EndIf
  If *prv = 0
    *new = CreateXMLNode(*par, 0, nodeType)
    If *new = 0
      ProcedureReturn 0
    EndIf
  Else
    *new = CreateXMLNode(*par, *prv, nodeType)
    If *new = 0
      ProcedureReturn 0
    EndIf
  EndIf
  ProcedureReturn XMLDeepCopy(*node, *new)
EndProcedure

Procedure.l ProcMvXMLNode(*node, *par, *prv)
  ret.l = ProcCpXMLNode(*node, *par, *prv)
  If ret > 0
    DeleteXMLNode(*node)
  EndIf
  ProcedureReturn ret
EndProcedure

CpXMLNode.ProtoCpXMLNode = @ProcCpXMLNode()
MvXMLNode.ProtoMvXMLNode = @ProcMvXMLNode()

xml move

Posted: Mon Dec 29, 2008 9:19 am
by afriend
Thanks fo posting. It appears your program cleans up a bit.