Page 1 of 1

XMLPrefs Example

Posted: Mon Aug 17, 2009 1:21 am
by Rescator
Here is something I quickly threw together.
Main reason was I kinda liked the XMLNodeFromPath() and wanted to experiment with it.

@freak: Any chance of some more functions that use NodeFromPath ?
In particular a Set and a Delete, so that one could simply do quick xml preference files using node paths. :)

These procedures gives you a easy way to do a XML based preference or config file.
Although there is a Main document node, a group node, and the entry nodes in this example, the code should support many many sub groups, so your not just limited to 3 levels like here.

Anyway, have fun with this one folks, experiment, improve upon, whatever ;)

Test XML:

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
<Main>
  <Group>
    <Entry>This is a simple test!</Entry>
    <Entry2>1</Entry2>
    <Entry3>This will be deleted!</Entry3>
  </Group>
</Main>
Source:

Code: Select all

;Public Domain.

EnableExplicit

Procedure.i XMLPrefsLoad(xml.i,filepath$)
 Protected result.i=#Null,bak$,len.i
 ;If prefs not found, restore backup if available.
 If len
  len+1
  bak$=Left(filepath$,Len(filepath$)-len)
 EndIf
 bak$+".bak"
 If FileSize(filepath$)<1
  RenameFile(bak$,filepath$)
 EndIf
 result=LoadXML(xml,filepath$)
 ProcedureReturn result
EndProcedure

Procedure.i XMLPrefsSave(xml.i,filepath$)
 Protected result.i=#False,bak$,len.i
 If IsXML(xml)
  len=Len(GetExtensionPart(filepath$))
  If len
   len+1
   bak$=Left(filepath$,Len(filepath$)-len)
  EndIf
  bak$+".bak"
  ;Delete any old backup.
  If FileSize(bak$)>-1
   DeleteFile(bak$)
  EndIf
  ;And make a new backup.
  RenameFile(filepath$,bak$)
  ;Save current prefs.
  FormatXML(xml,#PB_XML_ReFormat|#PB_XML_ReduceNewline,1)
  If Not SaveXML(xml,filepath$) ;If save failed then,
   If FileSize(filepath$)=0 ;If file exist and empty,
    DeleteFile(filepath$) ;delete it,
   EndIf
   RenameFile(bak$,filepath$) ;restore the backup.
  Else
   result=#True
  EndIf
 EndIf
 ProcedureReturn result
EndProcedure

Procedure.s XMLPrefsGetValue(xml.i,nodepath$)
 Protected text$,*rootnode,*node,pos.i,len.i
 If IsXML(xml)
  *rootnode=RootXMLNode(xml)
  If *rootnode
   *node=XMLNodeFromPath(*rootnode,nodepath$)
   If *node
    text$=Trim(GetXMLNodeText(*node))
    pos=1
    If (Left(text$,2)=#CRLF$)
     pos+2
    ElseIf (Left(text$,1)=#LF$) Or (Left(text$,1)=#CR$)
     pos+1
    EndIf
    len=Len(text$)
    If (Right(text$,2)=#CRLF$)
     len-4
    ElseIf (Right(text$,1)=#LF$) Or (Right(text$,1)=#CR$)
     len-3
    EndIf
    text$=Trim(Mid(GetXMLNodeText(*node),pos,len))
   EndIf
  EndIf
 EndIf
 ProcedureReturn text$
EndProcedure

Procedure.i XMLPrefsSetValue(xml.i,nodepath$,value$)
 Protected result=#False,text$,*rootnode,*node,*parentnode,n.i,i.i,path$,pos.i,name$
 If IsXML(xml)
  *rootnode=RootXMLNode(xml)
  If *rootnode
   *node=XMLNodeFromPath(*rootnode,nodepath$)
   If *node
    SetXMLNodeText(*node,value$)
    result=#True
   Else
    *parentnode=*rootnode
    pos=1
    n=CountString(nodepath$,"/")+1
    For i=2 To n
     pos=FindString(nodepath$,"/",pos+1)
     If pos=0
      pos=Len(nodepath$)
     EndIf
     path$=Left(nodepath$,pos)
     *node=XMLNodeFromPath(*parentnode,path$)
     If Not *node
      name$=StringField(nodepath$,i,"/")
      *node=CreateXMLNode(*parentnode,-1)
      If *node
       SetXMLNodeName(*node,name$)
       *parentnode=*node
      EndIf
     Else
      *parentnode=*node
     EndIf
     *node=XMLNodeFromPath(*rootnode,nodepath$)
     If *node
      SetXMLNodeText(*node,value$)
      result=#True
     EndIf
    Next
   EndIf
  EndIf
 EndIf
 ProcedureReturn result
EndProcedure

Procedure.i XMLPrefsDeleteValue(xml.i,nodepath$)
 Protected result=#False,*rootnode,*node
 If IsXML(xml)
  *rootnode=RootXMLNode(xml)
  If *rootnode
   *node=XMLNodeFromPath(*rootnode,nodepath$)
   If *node
    DeleteXMLNode(*node)
    result=#True
   EndIf
  EndIf
 EndIf
 ProcedureReturn result
EndProcedure

;You can use the rest of the XML functions normally, like:;
;XMLStatus() to check status, CreateXML() to create a new XML, FreeXML() to free the XML memory, and so on.

#XML_Prefs=1

Define prefs$,num.i,prefs_bak$,status.i
prefs$="test.xml"
If XMLPrefsLoad(#XML_Prefs,prefs$)
 status=XMLStatus(#XML_Prefs)
 If (status=#PB_XML_Success) Or (status=#PB_XML_NoElements)
  Debug XMLPrefsGetValue(#XML_Prefs,"/Main/Group/Entry") ;/main/node/value, IMPORTANT! Remember that XML is case sensitive.
  num=Val(XMLPrefsGetValue(#XML_Prefs,"/Main/Group/Entry2"))
  num+1
  XMLPrefsSetValue(#XML_Prefs,"/Main/Group/Entry2",Str(num))
  XMLPrefsDeleteValue(#XML_Prefs,"/Main/Group/Entry3")
 
  XMLPrefsSave(#XML_Prefs,prefs$)
 Else
  ;Show some XML error info here maybe?
 EndIf
 ;Free resources.
 FreeXML(#XML_Prefs)
EndIf
EDIT: Backupfile renaming was messed up, fixed.

Posted: Mon Aug 17, 2009 8:45 am
by Rescator
Backupfile renaming was messed up, fixed.

Posted: Wed Aug 19, 2009 9:32 pm
by SFSxOI
Great stuff, just what I needed. Thank You :)

Posted: Wed Aug 19, 2009 10:13 pm
by Rook Zimbabwe
I am sorry but the canadian company i4i holds all patents on XML and since you have mentioned its name you must now be killed by a horde of gibbering ninjaMonkeys!!!

(Translated: NICE WORK MAN!!!) :wink:

Posted: Wed Aug 19, 2009 10:57 pm
by Rescator
Thanks. I'm gonna use it in a few projects, but I'm not sure if I'll replace the good old .ini's yet.
This source lack certain things like enumeration and so on,
which is not so easy due to so many ways to store the data in XML.
But anyway, I hope people will get some cool ideas on how to do things that I didn't :)

Posted: Fri Aug 21, 2009 4:20 pm
by mk-soft
Very nice :D

I like attributes

Code: Select all

;Public Domain.

EnableExplicit

Procedure.i XMLPrefsLoad(xml.i,filepath$)
 Protected result.i=#Null,bak$,len.i
 ;If prefs not found, restore backup if available.
 If len
  len+1
  bak$=Left(filepath$,Len(filepath$)-len)
 EndIf
 bak$+".bak"
 If FileSize(filepath$)<1
  RenameFile(bak$,filepath$)
 EndIf
 result=LoadXML(xml,filepath$)
 If result = 0
  result = CreateXML(xml)
 EndIf
 
 ProcedureReturn result
EndProcedure

Procedure.i XMLPrefsSave(xml.i,filepath$)
 Protected result.i=#False,bak$,len.i
 If IsXML(xml)
  len=Len(GetExtensionPart(filepath$))
  If len
   len+1
   bak$=Left(filepath$,Len(filepath$)-len)
  EndIf
  bak$+".bak"
  ;Delete any old backup.
  If FileSize(bak$)>-1
   DeleteFile(bak$)
  EndIf
  ;And make a new backup.
  RenameFile(filepath$,bak$)
  ;Save current prefs.
  FormatXML(xml,#PB_XML_ReFormat|#PB_XML_ReduceNewline,1)
  If Not SaveXML(xml,filepath$) ;If save failed then,
   If FileSize(filepath$)=0 ;If file exist and empty,
    DeleteFile(filepath$) ;delete it,
   EndIf
   RenameFile(bak$,filepath$) ;restore the backup.
  Else
   result=#True
  EndIf
 EndIf
 ProcedureReturn result
EndProcedure

Procedure.s XMLPrefsGetValue(xml.i,nodepath$, attr$ = "Value")
 Protected text$,*rootnode,*node,pos.i,len.i
 If IsXML(xml)
  *rootnode=RootXMLNode(xml)
  If *rootnode
   *node=XMLNodeFromPath(*rootnode,nodepath$)
   If *node
    text$=GetXMLAttribute(*node, attr$)
   EndIf
  EndIf
 EndIf
 ProcedureReturn text$
EndProcedure

Procedure.i XMLPrefsSetValue(xml.i,nodepath$,value$,attr$="Value")
 Protected result=#False,text$,*rootnode,*node,*parentnode,n.i,i.i,path$,pos.i,name$
 If IsXML(xml)
  *rootnode=RootXMLNode(xml)
  If *rootnode
   *node=XMLNodeFromPath(*rootnode,nodepath$)
   If *node
    SetXMLAttribute(*node,attr$,value$)
    result=#True
   Else
    *parentnode=*rootnode
    pos=1
    n=CountString(nodepath$,"/")+1
    For i=2 To n
     pos=FindString(nodepath$,"/",pos+1)
     If pos=0
      pos=Len(nodepath$)
     EndIf
     path$=Left(nodepath$,pos)
     *node=XMLNodeFromPath(*parentnode,path$)
     If Not *node
      name$=StringField(nodepath$,i,"/")
      *node=CreateXMLNode(*parentnode,-1)
      If *node
       SetXMLNodeName(*node,name$)
       *parentnode=*node
      EndIf
     Else
      *parentnode=*node
     EndIf
     *node=XMLNodeFromPath(*rootnode,nodepath$)
     If *node
      SetXMLAttribute(*node,attr$,value$)
      result=#True
     EndIf
    Next
   EndIf
  EndIf
 EndIf
 ProcedureReturn result
EndProcedure

Procedure.i XMLPrefsDeleteValue(xml.i,nodepath$)
 Protected result=#False,*rootnode,*node
 If IsXML(xml)
  *rootnode=RootXMLNode(xml)
  If *rootnode
   *node=XMLNodeFromPath(*rootnode,nodepath$)
   If *node
    DeleteXMLNode(*node)
    result=#True
   EndIf
  EndIf
 EndIf
 ProcedureReturn result
EndProcedure

;You can use the rest of the XML functions normally, like:;
;XMLStatus() to check status, CreateXML() to create a new XML, FreeXML() to free the XML memory, and so on.

#XML_Prefs=1

Define prefs$,num.i,prefs_bak$,status.i
prefs$="test2.xml"
If XMLPrefsLoad(#XML_Prefs,prefs$)
 status=XMLStatus(#XML_Prefs)
 If (status=#PB_XML_Success) Or (status=#PB_XML_NoElements)
  Debug XMLPrefsGetValue(#XML_Prefs,"/Main/Group/Entry") ;/main/node/value, IMPORTANT! Remember that XML is case sensitive.
  num=Val(XMLPrefsGetValue(#XML_Prefs,"/Main/Group/Entry2"))
  num+1
  XMLPrefsSetValue(#XML_Prefs,"/Main/Group/Entry","Hello World")
  XMLPrefsSetValue(#XML_Prefs,"/Main/Group/Entry","2009", "Year")
  XMLPrefsSetValue(#XML_Prefs,"/Main/Group/Entry1",";)")
  XMLPrefsSetValue(#XML_Prefs,"/Main/Group/Entry2",Str(num))
  XMLPrefsDeleteValue(#XML_Prefs,"/Main/Group/Entry3")
 
  XMLPrefsSave(#XML_Prefs,prefs$)
 Else
  ;Show some XML error info here maybe?
 EndIf
 ;Free resources.
 FreeXML(#XML_Prefs)
EndIf
:wink:

P.S If XML document not exists i´m CreateXML

Posted: Fri Aug 21, 2009 11:52 pm
by mrjiles
I did a "fake" XML parser a while back :-) It only reads though.

http://www.purebasic.fr/english/viewtop ... highlight=