Page 1 of 4 1234>
Topic Options
#135405 - 2005-03-13 02:25 PM RFC: ReadXmlString/WriteXmlString
Shawn Administrator Offline
Administrator
*****

Registered: 1999-08-13
Posts: 8611
Realized I probably shoudn't hijack Chris's thread ... in regards to XML and as an offshoot to that thread ...

What I was thinking guys, was to create a matched pair of ReadProfileString/WriteProfileString work-alikes for XML files, to "ease" the interface when one just wants to read/write things like settings, here's a quick prototype of a matched set, plus a snippet of code to demonstrate usage.


break on

$filename = "e:\test.xml"

$xml = LoadXml($filename)

$= WriteXmlValue($xml, "korg/shawn/number", 119)
$= WriteXmlValue($xml, "korg/jose/number", 1772)
$= WriteXmlValue($xml, "korg/jooel/number", 2087)

?"Value=" ReadXmlValue($xml, "korg/jose/number")

SaveXml($xml, $filename)

$xml = 0

exit 1

---
[udf]
Code:

function LoadXml($filename)

dim $, $rootNode

$loadXml = CreateObject("Microsoft.XMLDOM");

if not $loadXml
return
endif

$= $loadXml.Load($filename)

endfunction


function WriteXmlValue($xml, $path, $value)

dim $p, $rootNode, $sectionNode, $parentNode, $childNode

$sectionNode = $xml.SelectSingleNode($path);

if not $sectionNode

$parentNode = $xml

for each $node in split($path,"/")

$p = $p + $node

$sectionNode = $xml.SelectSingleNode($p)

if not $sectionNode

$sectionNode = $xml.CreateElement($node)

$parentNode = $parentNode.AppendChild($sectionNode)

else

$parentNode = $sectionNode

endif

$p = $p + "/"

next

endif

if $sectionNode
$sectionNode.Text = $value
endif

endfunction

function SaveXml($xml, $filename)

$SaveXml = $xml.Save($filename);

endfunction


function ReadXmlValue($xml, $key, optional $defaultValue)

dim $sectionNode

$sectionNode = $xml.SelectSingleNode($key);

if not $sectionNode
$ReadXmlValue = $defaultValue;
else
$ReadXmlValue = $sectionNode.FirstChild.Text;
endif

endfunction



Thoughts ?

Top
#135406 - 2005-03-13 03:53 PM Re: RFC: ReadXmlString/WriteXmlString
Shawn Administrator Offline
Administrator
*****

Registered: 1999-08-13
Posts: 8611
Ok, here is an even more powerfull pair of UDF's ... it uses the XML path to read and write, much like a registry key path name. If the path one specifies doesn't exist, the UDF builds the path first, than pokes the value. Here's some examples:

$xmlFile = "e:\t.xml"

$= WriteXmlString($xmlFile, "form1/settings/left", 100)
$= WriteXmlString($xmlFile, "form1/settings/top", 200)

?"value=" ReadXmlString($xmlFile, "form1/settings/top")

[udf]
Code:

function WriteXmlString($filename, $path, $value)

dim $xmlDoc, $rootNode, $sectionNode;

$xmlDoc = CreateObject("Microsoft.XMLDOM");

if not $xmlDoc
return
endif

if not $xmlDoc.Load($filename)

$rootNode = $xmlDoc.createElement("configuration");
$= $xmlDoc.AppendChild($rootNode);

endif

$sectionNode = $xmlDoc.SelectSingleNode("/configuration/" + $path);

if not $sectionNode

$sectionNode = $xmlDoc.documentElement

for each $node in split($path,"/")

$childNode = $xmlDoc.CreateElement($node)

$= $sectionNode.AppendChild($childNode)

$sectionNode = $childNode

next

endif

$sectionNode.Text = $value;

$= $xmlDoc.Save($filename);

return

endfunction

function ReadXmlString($filename, $key, optional $defaultValue)

dim $xmlDoc, $sectionNode

$xmlDoc = CreateObject("Microsoft.XMLDOM")

if not $xmlDoc
return
endif

$= $xmlDoc.Load($filename)

$sectionNode = $xmlDoc.SelectSingleNode("/configuration/" + $key);

if not $sectionNode
$ReadXmlString = $defaultValue;
else
$ReadXmlString = $sectionNode.FirstChild.Text;
endif

endfunction



Top
#135407 - 2005-03-13 04:28 PM Re: RFC: ReadXmlString/WriteXmlString
Jose Offline
Seasoned Scripter
*****

Registered: 2001-04-04
Posts: 693
Loc: Buenos Aires - Argentina
Cool Shawn
I was thinking of doing SaveXML() but these two fit better.:).Agree 100% on keeping the writeprofilestring name structure in a very simple way.
It would be also intresting to include Chris idea about the type of XML (;$sFrom: 1 = File; 2 = HTTP; 3 = String) or just do another two like ReadXMLHTTP()-WriteXMLHTTP(). It is a different object thought CreateObject("Microsoft.XMLHTTP")

Have you tested speed on big updates?
_________________________
Life is fine.

Top
#135408 - 2005-03-13 04:33 PM Re: RFC: ReadXmlString/WriteXmlString
Shawn Administrator Offline
Administrator
*****

Registered: 1999-08-13
Posts: 8611
Jose and I were talking online on MSN, and we thought this strategy would be a more optimized way of writing to xml files, using Chris's LoadXml() idea in concert with these udf's, idea being something like:

$xml = LoadXml("t.xml")

WriteXmlString($xml, "shawn/jose", 100)

WriteXmlString($xml, "shawn/jose2/somesetting/option1", 200)

SaveXml($xml)

$xml = 0


Top
#135409 - 2005-03-13 04:58 PM Re: RFC: ReadXmlString/WriteXmlString
Shawn Administrator Offline
Administrator
*****

Registered: 1999-08-13
Posts: 8611
Ok, with apologies to Chris, borrowing his "loadxml" idea, here is a complete set of UDF's for loading/reading/writing/saving from XML files ... looks like this:

break on

$xml = LoadXml("e:\t.xml")

$= WriteXmlString($xml, "shawn/jose", 100)
$= WriteXmlString($xml, "shawn/jose/settings/form1/left", 123)

SaveXml($xml, "e:\t.xml")

$xml = 0

exit 1

[udf]
Code:

function LoadXml($filename)

dim $, $rootNode

$loadXml = CreateObject("Microsoft.XMLDOM");

if not $loadXml
return
endif

if not $loadXml.Load($filename)

$rootNode = $loadXml.createElement("root");

if $rootNode

$= $loadXml.AppendChild($rootNode);

endif

endif

endfunction

function SaveXml($xml, $filename)

$SaveXml = $xml.Save($filename);

endfunction

function WriteXmlString($xml, $path, $value)

dim $rootNode, $sectionNode;

$sectionNode = $xml.SelectSingleNode("/root/" + $path);

if not $sectionNode

$sectionNode = $xml.documentElement

for each $node in split($path,"/")

$childNode = $xml.CreateElement($node)

$sectionNode = $sectionNode.AppendChild($childNode)

next

endif

$sectionNode.Text = $value;

return

endfunction

function ReadXmlString($xml, $key, optional $defaultValue)

dim $sectionNode

$sectionNode = $xml.SelectSingleNode("/root/" + $key);

if not $sectionNode
$ReadXmlString = $defaultValue;
else
$ReadXmlString = $sectionNode.FirstChild.Text;
endif

endfunction



Top
#135410 - 2005-03-13 06:05 PM Re: RFC: ReadXmlString/WriteXmlString
Shawn Administrator Offline
Administrator
*****

Registered: 1999-08-13
Posts: 8611
hmmm, these UDF's need much more work ... found a few buggy-boos.
Top
#135411 - 2005-03-13 07:02 PM Re: RFC: ReadXmlString/WriteXmlString
Jose Offline
Seasoned Scripter
*****

Registered: 2001-04-04
Posts: 693
Loc: Buenos Aires - Argentina
I was trying to find out why is that when a value is not find the result is a new duplicated branch with new value included wich is wrong.

Here it says here
Quote:


The selectSingleNode method returns a Node object for the first descendant node to match the specified pattern. The one parameter of this method is an XSL pattern query. If no match is made, it returns null. This method is similar to the selectNodes method, but returns only the first node to match the pattern rather than all of them.




So when the there is no match the uds shoudnt do any save, instead should advice about the erro.

Another things to take into account:
- If the file does not exist and you use the write udf, the written file format is all flat (no tab nor enter between tags). I dont know if all interpreters white XML files in flat way or ppl accomadate them by hand.
- If the file is hand formatted after any modification the result are tags separted by tab.



BTW. About the new branch in case is does not exist I have found you can point out where that new branch can be placed, like this
$Elem = $xml.documentElement.firstchild.lastchild
I have dicovered this using $Elem.setAttribute(NAME,VALUE)

-----------------------------------------------------------
Oh I seen now, you have to split the path and see if all tags are present so as to create what is missing after the las known tag.
_________________________
Life is fine.

Top
#135412 - 2005-03-13 10:07 PM Re: RFC: ReadXmlString/WriteXmlString
Shawn Administrator Offline
Administrator
*****

Registered: 1999-08-13
Posts: 8611
Updated new set of UDF's in first post ...


Top
#135413 - 2005-03-13 10:53 PM Re: RFC: ReadXmlString/WriteXmlString
Allen Administrator Online   shocked
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4545
Loc: USA
Shawn, would you mind posting a sample xml file to show what kind of structure you are expecting?
Top
#135414 - 2005-03-13 11:33 PM Re: RFC: ReadXmlString/WriteXmlString
Shawn Administrator Offline
Administrator
*****

Registered: 1999-08-13
Posts: 8611
Im not expecting any structure ... the structure is user-defined, for example this sequence of calls:

$= WriteXmlValue($xml, "korg/shawn/number", 119)
$= WriteXmlValue($xml, "korg/shawn/lastname", "tassie")

will generate XML that looks like this:

Code:

<korg>
<shawn>
<number>119</number>
<lastname>tassie</lastname>
</shawn>
</korg>



-Shawn

Top
#135415 - 2005-03-15 01:44 AM Re: RFC: ReadXmlString/WriteXmlString
Jose Offline
Seasoned Scripter
*****

Registered: 2001-04-04
Posts: 693
Loc: Buenos Aires - Argentina
Since I am working with Open Office and has plenty of config files stored in xml I have found a very used feature wich is the attrib propertie. This propertie holds values within the XML tag.
Wrote two small UDFs for reading adn writting attributes by its path. WriteXMLattrib() and RearXMLattrib() .

Just run this code wich creates the xml file, if exist c:\temp.
Code:
  

Break on

$filename = "C:Temp\Shawn.xml"
$xml = LoadXml($filename)

$= WriteXmlValue($xml, "korg/shawn/City", "Toronto")
$= WriteXmlValue($xml, "korg/shawn/Country", "Canada")
$= WriteXmlValue($xml, "korg/shawn/Registred", "17/08/1999")

$= WriteXMLattrib($xml, "korg/shawn", "Id", "5200")
$= WriteXMLattrib($xml, "korg/shawn", "Age", "25")

SaveXml($xml, $filename)
$xml = 0


Open the file and take a look at the values Id and Age, they are attributes of Shawn.

Run this script to see those values.
Code:
 

Break on
$filename = "C:Temp\Shawn.xml"
$xml = LoadXml($filename)

$ShawnCity = ReadXmlValue($xml, "korg/shawn/City")
$ShawnCountry = ReadXmlValue($xml, "korg/shawn/Country")
$ShawnRegistred = ReadXmlValue($xml, "korg/shawn/Registred")


$ShawnId = RearXMLattrib($xml, "korg/shawn", "Id")
$ShawnAge = RearXMLattrib($xml, "korg/shawn", "Age")

? "Shawn Id Attribute= "+$ShawnId
? "Shawn Age Attribute= "+$ShawnAge

? "Shawn City Value= "+$ShawnCity
? "Shawn Country Value= "+$ShawnCountry
? "Shawn Registred Value= "+$ShawnRegistred

$xml = 0

Sleep 5



Functions:
Code:

Function LoadXml($filename)
Dim $, $rootNode
$loadXml = CreateObject("Microsoft.XMLDOM");
If NOT $loadXml
Return
EndIf
$= $loadXml.Load($filename)
EndFunction


Function WriteXmlValue($xml, $path, $value)
Dim $p, $rootNode, $sectionNode, $parentNode, $childNode
$sectionNode = $xml.SelectSingleNode($path);
If NOT $sectionNode
$parentNode = $xml
For Each $node In Split($path,"/")
$p = $p + $node
$sectionNode = $xml.SelectSingleNode($p)
If NOT $sectionNode
$sectionNode = $xml.CreateElement($node)
$parentNode = $parentNode.AppendChild($sectionNode)
Else
$parentNode = $sectionNode
EndIf
$p = $p + "/"
Next
EndIf
If $sectionNode
$sectionNode.Text = $value
EndIf
EndFunction

Function SaveXml($xml, $filename)
$SaveXml = $xml.Save($filename);
EndFunction

Function ReadXmlValue($xml, $key, optional $defaultValue)
Dim $sectionNode
$sectionNode = $xml.SelectSingleNode($key);
If NOT $sectionNode
$ReadXmlValue = $defaultValue;
Else
$ReadXmlValue = $sectionNode.FirstChild.Text;
EndIf
EndFunction

Function WriteXMLattrib($xml, $Path, $Attr, $Value)
$SelectionTag = $xml.getElementsByTagName($Path)
$AttrTag = $SelectionTag.item(0)
$eu = $AttrTag.SetAttribute($Attr,$Value);
EndFunction


Function RearXMLattrib($xml, $Path, $Attr)
$SelectionTag = $xml.getElementsByTagName($Path)
$AttrName = $SelectionTag.item(0)
$RearXMLattrib =$AttrName.getAttribute($Attr)
EndFunction



I think we are getting to an intresting point, this is very fast and looks good to me.

BTW: I cannot paste XML code cause we "Newbyes" dont have ATTRIBUTES !!! for that sort of pleasures.
_________________________
Life is fine.

Top
#135416 - 2005-03-15 08:40 AM Re: RFC: ReadXmlString/WriteXmlString
Lonkero Administrator Offline
KiX Master Guru
*****

Registered: 2001-06-05
Posts: 22346
Loc: OK
it has nothing to do with newbye stuff.
_________________________
!

download KiXnet

Top
#135417 - 2005-03-15 08:53 AM Re: RFC: ReadXmlString/WriteXmlString
Jose Offline
Seasoned Scripter
*****

Registered: 2001-04-04
Posts: 693
Loc: Buenos Aires - Argentina
Yeah I know I was kidding.
Do you know how to disable html Jooel?

Try to use a normal user (non-mod) and you will see what I mean.
_________________________
Life is fine.

Top
#135418 - 2005-03-15 09:12 AM Re: RFC: ReadXmlString/WriteXmlString
Lonkero Administrator Offline
KiX Master Guru
*****

Registered: 2001-06-05
Posts: 22346
Loc: OK
works just fine...

Edited by Jooel (2005-03-15 09:13 AM)
_________________________
!

download KiXnet

Top
#135419 - 2005-03-15 09:16 AM Re: RFC: ReadXmlString/WriteXmlString
Jose Offline
Seasoned Scripter
*****

Registered: 2001-04-04
Posts: 693
Loc: Buenos Aires - Argentina
Well this yould be the xml result file for last script. I can use it Jooel thanks man!.

Code:

- <korg>
- <shawn Id="5200" Age="25">
<City>Toronto</City>
<Country>Canada</Country>
<Registred>17/08/1999</Registred>
</shawn>
</korg>

_________________________
Life is fine.

Top
#135420 - 2005-03-15 06:38 PM Re: RFC: ReadXmlString/WriteXmlString
jtokach Offline
Seasoned Scripter
*****

Registered: 2001-11-15
Posts: 513
Loc: PA, USA
Is there a reason these aren't in the UDF forum?
_________________________
-Jim

...the sort of general malaise that only the genius possess and the insane lament.

Top
#135421 - 2005-03-15 06:40 PM Re: RFC: ReadXmlString/WriteXmlString
Shawn Administrator Offline
Administrator
*****

Registered: 1999-08-13
Posts: 8611
Because they're "evolving" ... ;0)
Top
#135422 - 2005-03-15 07:25 PM Re: RFC: ReadXmlString/WriteXmlString
jtokach Offline
Seasoned Scripter
*****

Registered: 2001-11-15
Posts: 513
Loc: PA, USA
Ah... (Sorry, didn't read the post dates!) The dog poo on my lawn is evolving too. =)

XML is the answer to all of my problems. Even dog poo.

Code:
<labrador>

<dogchow>
<poo>
<fluffydog>Wag tail</fluffydog>
<neighbors>Pinch nose</neighbors>
<jim>Ignore responsibility</jim>
<wife>Clean poo</wife>
</poo>
</dogchow>
</labrador>



Edited by jtokach (2005-03-15 07:27 PM)
_________________________
-Jim

...the sort of general malaise that only the genius possess and the insane lament.

Top
#135423 - 2005-03-15 07:49 PM Re: RFC: ReadXmlString/WriteXmlString
Shawn Administrator Offline
Administrator
*****

Registered: 1999-08-13
Posts: 8611
Les, you paying attention ? (Les just got a pup fyi)
Top
#135424 - 2005-03-15 07:57 PM Re: RFC: ReadXmlString/WriteXmlString
jtokach Offline
Seasoned Scripter
*****

Registered: 2001-11-15
Posts: 513
Loc: PA, USA
Congratulations Les!

Please note that the above does not apply to diapers... Replacing the <fluffydog> section with <baby>Crying</baby> blows the whole plan clear out of the water. As the matter of fact, it's untested, but implementing <jim>ignore responsibilities</jim> any where in the dirty diaper routine will most likely throw an exception at <wife>
_________________________
-Jim

...the sort of general malaise that only the genius possess and the insane lament.

Top
Page 1 of 4 1234>


Moderator:  Glenn Barnas, NTDOC, Arend_, Jochen, Radimus, Allen, ShaneEP, Ruud van Velsen, Mart 
Hop to:
Shout Box

Who's Online
1 registered (Allen) and 382 anonymous users online.
Newest Members
gespanntleuchten, DaveatAdvanced, Paulo_Alves, UsTaaa, xxJJxx
17864 Registered Users

Generated in 0.074 seconds in which 0.024 seconds were spent on a total of 12 queries. Zlib compression enabled.

Search the board with:
superb Board Search
or try with google:
Google
Web kixtart.org