XMLPrefs Example

Share your advanced PureBasic knowledge/code with the community.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

XMLPrefs Example

Post 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.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

Backupfile renaming was messed up, fixed.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

Great stuff, just what I needed. Thank You :)
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4322
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

Post 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:
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post 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 :)
User avatar
mk-soft
Always Here
Always Here
Posts: 6253
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Post 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
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mrjiles
Enthusiast
Enthusiast
Posts: 238
Joined: Fri Aug 18, 2006 7:21 pm
Location: IL

Post by mrjiles »

I did a "fake" XML parser a while back :-) It only reads though.

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