ShawnAdministrator
(KiX Supporter)
2005-03-13 02:25 PM
RFC: ReadXmlString/WriteXmlString

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 ?


ShawnAdministrator
(KiX Supporter)
2005-03-13 03:53 PM
Re: RFC: ReadXmlString/WriteXmlString

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




Jose
(Seasoned Scripter)
2005-03-13 04:28 PM
Re: RFC: ReadXmlString/WriteXmlString

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?


ShawnAdministrator
(KiX Supporter)
2005-03-13 04:33 PM
Re: RFC: ReadXmlString/WriteXmlString

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



ShawnAdministrator
(KiX Supporter)
2005-03-13 04:58 PM
Re: RFC: ReadXmlString/WriteXmlString

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




ShawnAdministrator
(KiX Supporter)
2005-03-13 06:05 PM
Re: RFC: ReadXmlString/WriteXmlString

hmmm, these UDF's need much more work ... found a few buggy-boos.

Jose
(Seasoned Scripter)
2005-03-13 07:02 PM
Re: RFC: ReadXmlString/WriteXmlString

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.


ShawnAdministrator
(KiX Supporter)
2005-03-13 10:07 PM
Re: RFC: ReadXmlString/WriteXmlString

Updated new set of UDF's in first post ...



AllenAdministrator
(KiX Supporter)
2005-03-13 10:53 PM
Re: RFC: ReadXmlString/WriteXmlString

Shawn, would you mind posting a sample xml file to show what kind of structure you are expecting?

ShawnAdministrator
(KiX Supporter)
2005-03-13 11:33 PM
Re: RFC: ReadXmlString/WriteXmlString

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


Jose
(Seasoned Scripter)
2005-03-15 01:44 AM
Re: RFC: ReadXmlString/WriteXmlString

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.


LonkeroAdministrator
(KiX Master Guru)
2005-03-15 08:40 AM
Re: RFC: ReadXmlString/WriteXmlString

it has nothing to do with newbye stuff.

Jose
(Seasoned Scripter)
2005-03-15 08:53 AM
Re: RFC: ReadXmlString/WriteXmlString

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.


LonkeroAdministrator
(KiX Master Guru)
2005-03-15 09:12 AM
Re: RFC: ReadXmlString/WriteXmlString

works just fine...

Jose
(Seasoned Scripter)
2005-03-15 09:16 AM
Re: RFC: ReadXmlString/WriteXmlString

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>



jtokach
(Seasoned Scripter)
2005-03-15 06:38 PM
Re: RFC: ReadXmlString/WriteXmlString

Is there a reason these aren't in the UDF forum?

ShawnAdministrator
(KiX Supporter)
2005-03-15 06:40 PM
Re: RFC: ReadXmlString/WriteXmlString

Because they're "evolving" ... ;0)

jtokach
(Seasoned Scripter)
2005-03-15 07:25 PM
Re: RFC: ReadXmlString/WriteXmlString

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>



ShawnAdministrator
(KiX Supporter)
2005-03-15 07:49 PM
Re: RFC: ReadXmlString/WriteXmlString

Les, you paying attention ? (Les just got a pup fyi)

jtokach
(Seasoned Scripter)
2005-03-15 07:57 PM
Re: RFC: ReadXmlString/WriteXmlString

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>


jtokach
(Seasoned Scripter)
2005-03-15 11:18 PM
Re: RFC: ReadXmlString/WriteXmlString

I'm playing around with this a bit, but Kix doesn't seem to handle this object model correctly?

Code:
$objXMLDoc = CreateObject("Microsoft.XMLDOM") 
$objXMLDoc.async = False
$=$objXMLDoc.load("C:\my.xml")

$j = " version = " + chr(34) +"1.0" + chr(34)

Dim $objNewPI, $currNode
$objNewPI = $objXMLDoc.createProcessingInstruction("xml", $j)
? "EE0:"@error
? "ES0:"@Serror

$d = $objXMLDoc.firstChild
? "EE1:"@error
? "ES1:"@Serror
$= $objXMLDoc.insertBefore ($objNewPI,$d)
$= $objXMLDoc.save("C:\my.xml")



Beyond that, it seems as though preservewhitespace is completely ignored. With the code you guys have so far, the indenting should be there...


Les
(KiX Master)
2005-03-15 11:50 PM
Re: RFC: ReadXmlString/WriteXmlString

$objXMLDoc.async = False

KiX does not have a keyword named "False"


jtokach
(Seasoned Scripter)
2005-03-16 12:05 AM
Re: RFC: ReadXmlString/WriteXmlString

Umm...
Code:
$objXMLDoc = CreateObject("Microsoft.XMLDOM") 
? "Before "$objXMLDoc.async
$objXMLDoc.async = False
? "After "$objXMLDoc.async



Jose
(Seasoned Scripter)
2005-03-16 12:15 AM
Re: RFC: ReadXmlString/WriteXmlString

Async

Code:
 
$objNewPI = $objXMLDoc.createProcessingInstruction("xml", $j)


Havent seen function within the XMLDOM object.


jtokach
(Seasoned Scripter)
2005-03-16 12:30 AM
Re: RFC: ReadXmlString/WriteXmlString

It adds that header line. Not of any value that I can see for our immediate needs. Got it working, but it's still freakin wierd. I puzzled as to the formatting???

Code:
function LoadXml($filename)
dim $, $rootNode, $objNewPI, $strType

$loadXml = CreateObject("Microsoft.XMLDOM");
$loadXml.async = False
$loadXml.preserverwhitespace = True

if not $loadXml
return
endif

$ = $loadXml.Load($filename)
$strType = " version = " + chr(34) + "1.0" + chr(34)
$objNewPI = $loadXml.createProcessingInstruction("xml", $strType)
$ = $loadXml.insertBefore ($objNewPI,$objXMLDoc.firstChild)

endfunction



Jose
(Seasoned Scripter)
2005-03-16 01:59 AM
Re: RFC: ReadXmlString/WriteXmlString

I see your point Jim, sorry I didnt undertand.


Quote:


I'm playing around with this a bit, but Kix doesn't seem to handle this object model correctly?




You are right.
The header idea is very good but does not work as it should. Me cannot make it work either.


Code:
  

$objNewPI = $loadXml.createProcessingInstruction("xml", $strType)


I get @error=2147352570

Code:
 

$ = $loadXml.insertBefore ($objNewPI,$objXMLDoc.firstChild)


I get @error=6


I have tryed with the XMLDOM error method ($objXMLDoc.parseError) but nothing. All DOM errors=0.

I think it is compulsory for these udf´s to include this feature and we should find out how. VBScrit source.

Any ideas guys? Can anyone else give a try?


Jose
(Seasoned Scripter)
2005-03-16 10:58 AM
Re: RFC: ReadXmlString/WriteXmlString

Talking to Jooel he suggeted to use the old friend writeline() to write the header.
I am more the opinion of using the same object developed for that purpose but this particular code seems to be stucked using kix.

Thoughts?


jtokach
(Seasoned Scripter)
2005-03-16 05:54 PM
Re: RFC: ReadXmlString/WriteXmlString

Jose, that header code works for me, not sure why your seeing those errors.

Regarding writeline(), I'm half tempted to say screw xmldom object model and do everything with arrays, readline and writeline...

Regarding formatting, the single line seems to be the only output xmldom is capable of producing. Formatting is a separate process: Somewhat automated way of formatting .xml

It's in VB, but at a glance, it looks like it can be converted.


ShawnAdministrator
(KiX Supporter)
2005-03-16 07:24 PM
Re: RFC: ReadXmlString/WriteXmlString

Jim, not too sure I would dismiss XML so quickly. Personally, I'm hoping to get some screaming performance gains versus the builtin WriteLine and WriteProfileString functions. Although I have no data to back this up, the Kixtart builtins are slow as hell (especially writing stuff). Think some benchmarking is in order.

The other thing ... wish I could figure-out a way to get the output XML properly formatted. When notepadding the result, all the data is scrunched into one long line. Must be a way to introduce some formatting in there.


LonkeroAdministrator
(KiX Master Guru)
2005-03-16 07:52 PM
Re: RFC: ReadXmlString/WriteXmlString

so, you say com stuff is faster than writeline?
uuh...

and who did say anything about dismissing xml?
xml is lot more than the lame com stuff used in this thread.


Jose
(Seasoned Scripter)
2005-03-16 08:38 PM
Re: RFC: ReadXmlString/WriteXmlString

Quote:


xml is lot more than the lame com stuff used in this thread.





I dont like this.


LonkeroAdministrator
(KiX Master Guru)
2005-03-16 08:45 PM
Re: RFC: ReadXmlString/WriteXmlString

I knew you wouldn't like it.
you like the com-object.
but finally you have to admit that xml is just pure text and nothing much more.


Jose
(Seasoned Scripter)
2005-03-16 08:55 PM
Re: RFC: ReadXmlString/WriteXmlString

Com or text is the same as you said, and there sure are thrid party ways of doing it too.

What I dont like is you making that opinion about something I had involved in.


jtokach
(Seasoned Scripter)
2005-03-16 10:37 PM
Re: RFC: ReadXmlString/WriteXmlString

Quote:

Jim, not too sure I would dismiss XML so quickly. Personally, I'm hoping to get some screaming performance gains versus the builtin WriteLine and WriteProfileString functions. Although I have no data to back this up, the Kixtart builtins are slow as hell (especially writing stuff). Think some benchmarking is in order.




If it wasn't so complicated, I wouldn't mind so much, but it sucks and something seems to be unpredictable. Again, I renew my request for builtin xml support in Kix. =)

Quote:

The other thing ... wish I could figure-out a way to get the output XML properly formatted. When notepadding the result, all the data is scrunched into one long line. Must be a way to introduce some formatting in there.



I posted this in the previous post. It's written in VB. It is terribly inconvenient but not sure it's that big of an issue. We'll need to stick to IE until someone can translate that VB code. I started, but I can't find a suitable replacement for the TypeOf statements, yet...


jtokach
(Seasoned Scripter)
2005-03-17 06:09 PM
Re: RFC: ReadXmlString/WriteXmlString

Hail to the King Baby!

-Formatting hooked up! (Needed to apply XSL)
-Updated all code for Option Explicit

Code:
break on

$nul=SetOption("ASCII","On")
$nul=SetOption("Explicit","On")

Dim $filename,$xml,$

$filename = "C:\HailToTheKingBaby.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

function LoadXml($filename)
dim $, $rootNode, $objNewPI, $strType

$loadXml = CreateObject("Microsoft.XMLDOM")
$loadXml.async = False
$loadXml.preserverwhitespace = True

if not $loadXml
return
endif

$ = $loadXml.Load($filename)
endfunction


Function FormatXML($objXMLDOM)
Dim $,$strXSL,$objXSL
;Create and Load XSL
; <?xml version="1.0" encoding="UTF-8"?>
; <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
; <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
; <xsl:template match="/ | @* | node()">
; <xsl:copy>
; <xsl:apply-templates select="@* | node()" />
; </xsl:copy>
; </xsl:template>
; </xsl:stylesheet>

$strXSL = "<?xml version=" + chr(34) + "1.0" + chr(34) + " encoding=" +
chr(34) + "UTF-8" + chr(34) + "?>" + @CRLF
$strXSL = $strXSL + "<xsl:stylesheet version=" + chr(34) + "1.0" + chr(34) +
" xmlns:xsl=" + chr(34) + "http://www.w3.org/1999/XSL/Transform" +
chr(34) + ">" + @CRLF
$strXSL = $strXSL + "<xsl:output method=" + chr(34) + "xml" + chr(34) +
" version=" + chr(34) + "1.0" + chr(34) + " encoding=" + chr(34) +
"UTF-8" + chr(34) + " indent=" + chr(34) + "yes" + chr(34) + "/>" + @CRLF
$strXSL = $strXSL + "<xsl:template match=" + chr(34) + "/ | @@* | node()" +
chr(34) + ">" + @CRLF
$strXSL = $strXSL + "<xsl:copy>"+ @CRLF
$strXSL = $strXSL + "<xsl:apply-templates select=" + chr(34) +
"@@* | node()" + chr(34) + " />"+ @CRLF
$strXSL = $strXSL + "</xsl:copy>"+ @CRLF
$strXSL = $strXSL + "</xsl:template>"+ @CRLF
$strXSL = $strXSL + "</xsl:stylesheet>"

;? "XLM Stylesheet: " + @CRLF + $strXSL

$objXSL = CreateObject("Microsoft.XMLDOM")
$objXSL.async = false
$=$objXSL.loadXML($strXSL)

;Transform file
$objXMLDOM.TransformNodeToObject ($objXSL, $objXMLDOM)
$formatXML = $objXMLDOM
EndFunction


function WriteXmlValue($xml, $path, $value)
dim $p, $rootNode, $sectionNode, $parentNode, $childNode,$node
$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)
$xml = formatXML($xml)
$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



jtokach
(Seasoned Scripter)
2005-03-17 06:57 PM
Re: RFC: ReadXmlString/WriteXmlString

Jose, I updated your attrib UDF's. Also renamed the one from Rear to Read (I assumed that was a typo.)

Code:
Function WriteXMLattrib($xml, $Path, $Attr, $Value)

Dim $SelectionTag,$AttrTag,$,$eu
$SelectionTag = $xml.getElementsByTagName($Path)
$AttrTag = $SelectionTag.item(0)
If @Serror = "Member not found."
$= WriteXmlValue($xml, $path, "")
$SelectionTag = $xml.getElementsByTagName($Path)
$AttrTag = $SelectionTag.item(0)
EndIf
$eu = $AttrTag.SetAttribute($Attr,$Value)
EndFunction


Function ReadXMLattrib($xml, $Path, $Attr)
Dim $SelectionTag,$AttrName
$SelectionTag = $xml.getElementsByTagName($Path)
$AttrName = $SelectionTag.item(0)
If @Serror = "Member not found."
$ReadXMLattrib = ""
Exit @Error
Else
$ReadXMLattrib =$AttrName.getAttribute($Attr)
EndIf
EndFunction



NTDOCAdministrator
(KiX Master)
2005-03-17 07:07 PM
Re: RFC: ReadXmlString/WriteXmlString

FYI - Link to XSL that Jim refers to.

http://www.w3.org/Style/XSL/

Learning link
http://www.w3schools.com/xsl/

XSL Frequently Asked Questions
http://www.dpawson.co.uk/xsl/xslfaq.html


Jose
(Seasoned Scripter)
2005-03-17 08:20 PM
Re: RFC: ReadXmlString/WriteXmlString



Jim you have done a fantastic job man!!

LOL Rear. Havent realized . Silly me
ReadXMLattrib() looks much better.


Jose
(Seasoned Scripter)
2005-03-17 09:22 PM
Re: RFC: ReadXmlString/WriteXmlString

Jim:
I have changed two things in the attrib functions.
- I have spanish languaje so changed to @error in case path not exist.
- took the $eu off and replaced with $Write

Code:
  
Function WriteXMLattrib($xml, $Path, $Attr, $Value)

Dim $SelectionTag,$AttrTag,$,$Write

$SelectionTag = $xml.getElementsByTagName($Path)

$AttrTag = $SelectionTag.item(0)

If @ERROR = "-2147352573"

$= WriteXmlValue($xml, $path, "")

$SelectionTag = $xml.getElementsByTagName($Path)

$AttrTag = $SelectionTag.item(0)

EndIf

$write = $AttrTag.SetAttribute($Attr,$Value)

EndFunction


Function ReadXMLattrib($xml, $Path, $Attr)

Dim $SelectionTag,$AttrName

$SelectionTag = $xml.getElementsByTagName($Path)

$AttrName = $SelectionTag.item(0)

If @ERROR = "-2147352573"

$ReadXMLattrib = ""

Exit @Error

Else

$ReadXMLattrib =$AttrName.getAttribute($Attr)

EndIf

EndFunction



jtokach
(Seasoned Scripter)
2005-03-17 10:35 PM
Re: RFC: ReadXmlString/WriteXmlString

Jose,

Sorry for being so ignorant!!! It didn't even occur to me that @serror would be different b/w languages.

I think we need some more though as to how this is going to progress. I'm thinking we need and EnumXML().

Also, not sure that LoadXML and SaveXML are the best method of approaching this. Shouldn't these be built right into all of the Write and Read functions; like ReadProfileString and WriteProfileString? Granted that there would be much more overhead, but much simpler to write code with. I guess that's where you'd lose your performance gain, eh Shawn? But, at least I'd be able to perform a Read operation right after write operation because the data is immediately commited to disk.

Current:
Code:

LoadXML()
Get data...
WriteXMLValue()
Get more data...
WriteXMLValue()
SaveXML()

and

LoadXML()
ReadXMLValue()
ReadXMLValue()
SaveXML()



Jim Preferred:
Code:

WriteXMLValue()
ReadXMLValue()
WriteXMLValue()
ReadXMLValue()
ReadXMLValue()
WriteXMLValue()



jtokach
(Seasoned Scripter)
2005-03-18 01:10 AM
Re: RFC: ReadXmlString/WriteXmlString

Regarding EnumXML(), here's where I'm at:

Code:
Function EnumXML($xml)
Dim $i,$a,$NodeList

$NodeList = $xml.getElementsByTagName("*")
For Each $i In $NodeList
? "Element " +$i.tagName
;? "attributes: " $i.attributes
;? "baseName: " $i.baseName
;? "childNodes: " $i.childNodes
;? "dataType: " $i.dataType
;? "definition: " $i.definition
? "firstChild: " $i.firstChild.nodeName
? "lastChild: " $i.lastChild.nodeName
;? "namespaceURI: " $i.namespaceURI
? "nextSibling: " $i.nextSibling.nodeName
;? "nodeName: " $i.nodeName
;? "nodeType: " $i.nodeType
;? "nodeTypeString: " $i.nodeTypeString
;? "nodeValue: " $i.nodeValue
;? "ownerDocument: " $i.ownerDocument
? "parentNode: " $i.parentNode.nodeName
;? "parsed: " $i.parsed
;? "prefix: " $i.prefix
;? "previousSibling: " $i.previousSibling.nodeName
;? "specified: " $i.specified
;? "tagName: " $i.tagName
;? "text: " $i.text
;? "xml: " $i.xml
??
Next


;? "root: "$xml.documentElement.NodeName

;$a = xml_doc.getElementsByTagName("*")
;for each $i in $a
; item($i).text
; next
; for each $i in $xml.documentElement.childNodes
; Dim $k,$m
; ? "lvl1: " $xml.documentElement.NodeName + "/" + $i.nodeName
; ;GetXMLChildElements($xml,$xml.documentElement.NodeName + "/" + $i.nodeName)
; next
EndFunction




ShawnAdministrator
(KiX Supporter)
2005-03-18 01:25 AM
Re: RFC: ReadXmlString/WriteXmlString

We did originally perform the Load and Save in WriteXMLValue, loading and saving on every write, then just decided that that wasn't very efficient, so removed - didn't perform any bench-marking or anything, might not be too bad. Doing that load and save certainly makes the whole thing easier to use - for sure.

jtokach
(Seasoned Scripter)
2005-03-18 05:15 PM
Re: RFC: ReadXmlString/WriteXmlString

EDIT1: Renamed some stuff and added some stuff.
EDIT2: Added Remove* functions (Jose suggestion)
Renamed functions from *Attribute to *Attr

Shawn, if there's sufficient reason to, we can 'overload' these functions by allowing the source argument to be either a path\filename, an XMLDOM object, or an XML string. This raises the complexity of the functions, but also addresses performance and increases usability.

All, I'm envisioning these functions as a cross between the _profilestring functions and the registry functions. Kinda mimics real life as XML seems to be a cross between INI and a hierarchal db like the REG. Here's how I see it, please comment:

Core functions (We have a solid base on most of this already)
Code:
  

LoadXML() - Load an existing .XML file, instantiate XMLDOM object for use regardless of file existance.
SaveXML() - Saves an XMLDOM object
FormatXML() - Formats the output style of an XMLDOM object to the standard

EnumXMLElement() - Enums child elements of a given element
EnumXMLAttr() - Enums all attributes of an element

CreateXMLElement() - Creates an empty element pair
RemoveXMLElement() - Deletes an XML element (Recursively?)

WriteXMLValue() - Writes a value to an XML element
ReadXMLValue() - Reads the value of an XML element

WriteXMLAttr() - Writes an attribute to an XML element
ReadXMLAttr() - Read a specific attribute of an XML element
RemoveXMLAttr() - Deletes an XML element attribut


Secondary functions
Code:
 

ApplyXSL() - Applies an XSL template. (Much potential here for an expanded set, see
http://www.devguru.com/Technologies/xslt/quickref/xslt_index.html
or NTDOC's post above.
FilterXML() - Apply a filter to an XMLDOM object. (Search the db. XSL related.)



ShawnAdministrator
(KiX Supporter)
2005-03-18 05:28 PM
Re: RFC: ReadXmlString/WriteXmlString

I'm cool with overloading, good idea, so the write overloads would look like:

WriteXmlValue(string, string, variant)

-and-

WriteXmlValue(object, string, variant)

Where if the first parm is a string, it means its a filename, and if its an object, means its a xml object. ja ?


jtokach
(Seasoned Scripter)
2005-03-18 05:40 PM
Re: RFC: ReadXmlString/WriteXmlString

Bingo. Even more than that though.

WriteXmlValue(string, string, variant)
WriteXmlValue(object, string, variant)

and

WriteXmlValue(xmlstring, string, variant)

Where if instr(xmlstring,"<")
Not a filename, but an XML string of elements. So you could build your XML file in a string and then do a $=$objXML.loadXML($strXML) (note the loadXML method instead of .load)

I really haven't thought out what this would buy us as brainstorming doesn't lend well to rational thought. But, I think later it may handy when dealing with creating XSL on the fly or creating new .XML files from portions of existing XML.

I forgot to add WriteXmlValue() the previous list... Done.


jtokach
(Seasoned Scripter)
2005-03-18 05:48 PM
Re: RFC: ReadXmlString/WriteXmlString

And one more request... (don't crucify me) but can we possibly not use Optional args? I plan on rewriting these in .VBS and it just makes life easier.

jtokach
(Seasoned Scripter)
2005-03-18 06:55 PM
Re: RFC: ReadXmlString/WriteXmlString - division of labor

I'm going to start working on EnumXMLElement() and
EnumXMLAttribute(). If someone is writing code on this, please let us know what you're doing.

Both of these will return an array on success, or a null string otherwise (with errorlevel for further definition)


Jose
(Seasoned Scripter)
2005-03-18 07:02 PM
Re: RFC: ReadXmlString/WriteXmlString

Not me Jim I think we hould also add these two.

RemoveXMLElement()
RemoveXMLattr()

I have tryed the second one. Coudnt afford using optional arg Jim .


Code:
  

Function RemoveXMLattr($xml, $Path, $attr, optional $id)

Dim $SelectionTag,$AttrTag,$erase

$SelectionTag = $xml.getElementsByTagName($Path)

If $id=""
$id=0
EndIf

$AttrTag = $SelectionTag.item($id)

$erase = $AttrTag.removeAttribute($attr)

EndFunction



Posting sample.


jtokach
(Seasoned Scripter)
2005-03-18 07:14 PM
Re: RFC: ReadXmlString/WriteXmlString

Good call Jose, I'll add them to that list.

Yeah, sometimes you can't get around using optionals. In that case, with .VBS, I force sending all arguments where optionals contain NULL.


Jose
(Seasoned Scripter)
2005-03-18 07:24 PM
Re: RFC: ReadXmlString/WriteXmlString

Te optional comes cause you could have a sample like this:
Code:

<?xml version="1.0" encoding="UTF-8" ?>
<Albums>
<Album ref="CD142" category="Folk">
<title>Boil The Breakfast Early</title>
<artist>The Chieftains</artist>
</Album>
<Album ref="CD720" category="Pop">
<title>Come On Over</title>
<artist>Shania Twain</artist>
</Album>
<Album ref="CD024" category="Country">
<title>Red Dirt Girl</title>
<artist>Emmylou Harris</artist>
</Album>
</Albums>



Code:
  
$=RemoveXMLattr($xml, "Albums/Album", "category", 0)


In wich case you have to indicate the att id to erase it. 0 should remove category="Folk" in this case.
Maybe would be better to search for the attr, get the id and then arease it if you dont now it.


AllenAdministrator
(KiX Supporter)
2005-03-18 07:39 PM
Re: RFC: ReadXmlString/WriteXmlString

Code:
 
<Album ref="CD142" category="Folk"> <title>Boil The Breakfast Early</title> <artist>The Chieftains</artist> </Album>



ahh just what I was wondering about earlier... Shawn, Jose's code above is exactly where I was going with my earlier question about the XML format you are expecting. In this example there are values defined within the Album (ref="CD142"), and then child attributes like title and artitist.

I'll be the first one to admit, I don't know a whole lot about XML, but would it be easiest to say the format of the XML is expected to be only one way or another, or are the UDFs already taking in consideration the altering data formats?


Les
(KiX Master)
2005-03-18 08:00 PM
Re: RFC: ReadXmlString/WriteXmlString

Pardon me for jumping in this late in the game. I thought I read early on that the objective was to "emulate" the INI file handling like WriteProfileString() does. Now I see it is more like WriteLine() whereby the file needs to be opened, read, written, closed, etc., and now something to remove elements? I know I did not read every word in this thread but I don't recall a change of objective stated anywhere, just creep.

Jose
(Seasoned Scripter)
2005-03-18 08:00 PM
Re: RFC: ReadXmlString/WriteXmlString

Allen:
The thing about XML is that you are free to format it as you wish. There is not defined structure to use it as an mdb database.
You can have either different child names like this, used in a straight way as ini.
Code:
  

- <korg>
- <shawn>
<number>119</number>
</shawn>
- <jose>
<number>1772</number>
</jose>
- <jooel>
<number>2087</number>
</jooel>
</korg>



Or you can have same childs widh are defined by different attributes. Like this.
Code:
  

- <Albums>
- <Album ref="CD142" category="Folk">
<title>Boil The Breakfast Early</title>
<artist>The Chieftains</artist>
</Album>
- <Album ref="CD720" category="Pop">
<title>Come On Over</title>
<artist>Shania Twain</artist>
</Album>
- <Album ref="CD024" category="Country">
<title>Red Dirt Girl</title>
<artist>Emmylou Harris</artist>
</Album>
</Albums>



In wich case ref="CD142" is an attribute for that particular album.

This is what I have seen by now about XLM I think none of us is expert we are just getting into knowing it.


jtokach
(Seasoned Scripter)
2005-03-18 08:01 PM
Re: RFC: ReadXmlString/WriteXmlString

Allen,

This is why I'm modeling after INI+REG. You can combine both styles, and most programmer do. So like the REG functions: EnumKey, EnumValues, do something. Given the current setup: EnumXMLElements, ReadXMLValue, EnumXMLAttr.

The extra step is required b/c XML is basically a combo of INI and hierarcal REG.


jtokach
(Seasoned Scripter)
2005-03-18 08:18 PM
Re: RFC: ReadXmlString/WriteXmlString

Les, the *ProfileString do the same thing, although Kix does the work of open and close behind the scenes. Since we can't operate at that level, we have no choice but to Open, Read/Write, Close somewhere, either internal to the function or external to it.

I asked Shawn, in a previous post, why LoadXML and SaveXML were seperated, and he stated for effeciency. Our collective agreement has been to overload the functions so that both methods (writeline type and *profilestring) are available.


Jose
(Seasoned Scripter)
2005-03-18 08:31 PM
Re: RFC: ReadXmlString/WriteXmlString

And.....I dont think that any other languajes that invoke XMLDOM are using it other that we are trying to use now, its XMLDOM way.


Jose
(Seasoned Scripter)
2005-03-18 08:39 PM
Re: RFC: ReadXmlString/WriteXmlString

Jim?
Quote:


RemoveXMLElement() - Deletes an XML element (Recursively?)




What do you mean by Recursively? sorry if I dont get it.


jtokach
(Seasoned Scripter)
2005-03-18 08:47 PM
Re: RFC: ReadXmlString/WriteXmlString

Jose, not sure if the delete methods of XMLDOM will allow you to delete an element that has children. Haven't done any research into it yet. I think it does which would make it recursive, in a sense.

jtokach
(Seasoned Scripter)
2005-03-18 08:52 PM
Re: RFC: ReadXmlString/WriteXmlString

Here's all of what we have so far. Some functions have been renamed from their original.

LoadXML() - Load an existing .XML file, instantiate XMLDOM object for use regardless of file existance.
SaveXML() - Saves an XMLDOM object
FormatXML() - Formats the output style of an XMLDOM object to the standard

EnumXMLElement() - Enums child elements of a given element
EnumXMLAttr() - Enums all attributes of an element

CreateXMLElement() - Creates an empty element pair
RemoveXMLElement() - Deletes an XML element (Recursively?)

WriteXMLValue() - Writes a value to an XML element
ReadXMLValue() - Reads the value of an XML element

WriteXMLAttr() - Writes an attribute to an XML element
ReadXMLAttr() - Read a specific attribute of an XML element
RemoveXMLAttr() - Deletes an XML element attribut


Secondary functions

ApplyXSL() - Applies an XSL template. (Much potential here for an expanded set, see
http://www.devguru.com/Technologies/xslt/quickref/xslt_index.html
or NTDOC's post above.
FilterXML() - Apply a filter to an XMLDOM object. (Search the db. XSL related.)


Code:
; CreateXMLElement() - Creates an empty element pair

Function CreateXMLElement()

EndFunction

; EnumXMLAttr() - Enums all attributes of an element
Function EnumXMLAttr()

EndFunction

; EnumXMLElement() - Enums child elements of a given element
Function EnumXMLElement()

EndFunction

;FormatXML() - Formats the output style of an XMLDOM object to the standard
Function FormatXML($objXMLDOM)
Dim $,$strXSL,$objXSL
;Create and Load XSL
; <?xml version="1.0" encoding="UTF-8"?>
; <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
; <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
; <xsl:template match="/ | @* | node()">
; <xsl:copy>
; <xsl:apply-templates select="@* | node()" />
; </xsl:copy>
; </xsl:template>
; </xsl:stylesheet>

$strXSL = "<?xml version=" + chr(34) + "1.0" + chr(34) + " encoding=" +
chr(34) + "UTF-8" + chr(34) + "?>" + @CRLF
$strXSL = $strXSL + "<xsl:stylesheet version=" + chr(34) + "1.0" + chr(34) +
" xmlns:xsl=" + chr(34) + "http://www.w3.org/1999/XSL/Transform" +
chr(34) + ">" + @CRLF
$strXSL = $strXSL + "<xsl:output method=" + chr(34) + "xml" + chr(34) +
" version=" + chr(34) + "1.0" + chr(34) + " encoding=" + chr(34) +
"UTF-8" + chr(34) + " indent=" + chr(34) + "yes" + chr(34) + "/>" + @CRLF
$strXSL = $strXSL + "<xsl:template match=" + chr(34) + "/ | @@* | node()" +
chr(34) + ">" + @CRLF
$strXSL = $strXSL + "<xsl:copy>"+ @CRLF
$strXSL = $strXSL + "<xsl:apply-templates select=" + chr(34) +
"@@* | node()" + chr(34) + " />"+ @CRLF
$strXSL = $strXSL + "</xsl:copy>"+ @CRLF
$strXSL = $strXSL + "</xsl:template>"+ @CRLF
$strXSL = $strXSL + "</xsl:stylesheet>"

;? "XLM Stylesheet: " + @CRLF + $strXSL

$objXSL = CreateObject("Microsoft.XMLDOM")
$objXSL.async = false
$=$objXSL.loadXML($strXSL)

;Transform file
$objXMLDOM.TransformNodeToObject ($objXSL, $objXMLDOM)
$formatXML = $objXMLDOM
EndFunction

;LoadXML() - Load an existing .XML file, instantiate XMLDOM object for use
;regardless of file existance.
Function LoadXML($filename)
dim $, $rootNode, $objNewPI, $strType

$loadXml = CreateObject("Microsoft.XMLDOM")
$loadXml.async = False
$loadXml.preserverwhitespace = True

if not $loadXml
return
endif

$ = $loadXml.Load($filename)
EndFunction

; ReadXMLAttr() - Read a specific attribute of an XML element
Function ReadXMLAttr($xml, $Path, $Attr)
Dim $SelectionTag,$AttrName
$SelectionTag = $xml.getElementsByTagName($Path)
$AttrName = $SelectionTag.item(0)
If @Serror = "Member not found."
$ReadXMLAttr = ""
Exit @Error
Else
$ReadXMLAttr =$AttrName.getAttribute($Attr)
EndIf
EndFunction

;ReadXMLElement() - Reads the value of an XML element
Function ReadXMLValue($xml, $key, optional $defaultValue)
Dim $sectionNode
$sectionNode = $xml.SelectSingleNode($key)
If not $sectionNode
$ReadXmlValue = $defaultValue
Else
$ReadXmlValue = $sectionNode.FirstChild.Text
EndIf
EndFunction

; RemoveXMLAttr() - Deletes an XML element attribute
Function RemoveXMLAttr($xml, $Path, $attr, optional $id)
Dim $SelectionTag,$AttrTag,$erase
$SelectionTag = $xml.getElementsByTagName($Path)
If $id=""
$id=0
EndIf
$AttrTag = $SelectionTag.item($id)
$erase = $AttrTag.removeAttribute($attr)
EndFunction

; RemoveXMLElement() - Deletes an XML element (Recursively?)
Function RemoveXMLElement()

EndFunction

;SaveXML() - Saves an XMLDOM object to a file
; Requires: FormatXML()
Function SaveXML($xml, $filename)
$xml = FormatXML($xml)
$SaveXml = $xml.Save($filename)
EndFunction

; WriteXMLAttr() - Writes an attribute to an XML element
Function WriteXMLAttr($xml, $Path, $Attr, $Value)
Dim $SelectionTag,$AttrTag,$,$eu
$SelectionTag = $xml.getElementsByTagName($Path)
$AttrTag = $SelectionTag.item(0)
If @Serror = "Member not found."
$ = WriteXmlValue($xml, $path, "")
$SelectionTag = $xml.getElementsByTagName($Path)
$AttrTag = $SelectionTag.item(0)
EndIf
$eu = $AttrTag.SetAttribute($Attr,$Value)
EndFunction

; WriteXMLValue() - Writes a value to an XML element
Function WriteXMLValue($xml, $path, $value)
dim $p, $rootNode, $sectionNode, $parentNode, $childNode,$node
$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


; ******************************************************************************
; ApplyXSL() - Applies an XSL template. (Much potential here for an expanded
; set, see http://www.devguru.com/Technologies/xslt/quickref/xslt_index.html
Function ApplyXSL()

EndFunction

; FilterXML() - Apply a filter to an XMLDOM object. (Search the db. XSL related.)
Function FilterXML()

EndFunction



Jose
(Seasoned Scripter)
2005-03-18 09:06 PM
Re: RFC: ReadXmlString/WriteXmlString

This is quite an achievement man!!
From nothing we have plenty of stuff now.



About the delete method I think it should delete both element and children I will se if I can get along with it, if not I shout it out.

Ahh...remember to update Write-ReadXMLAttr() for the languaje issue. Remember "Member not found."?



jtokach
(Seasoned Scripter)
2005-03-18 09:27 PM
Re: RFC: ReadXmlString/WriteXmlString

Damn. I thought I did...

Here's the Overload code implemented into a function. Works great. I guess I'll retrofit all of the function to use this before I tackle the other funcs. I'll update the post aobve with the language changes and this.
Code:
; WriteXMLValue() - Writes a value to an XML element
Function WriteXMLValue($source, $path, $value)
dim $, $p, $rootNode, $sectionNode, $parentNode, $childNode, $node, $xml
; Begin Overloaded Var Sorting
If VarType($source) = 9
; An object was passed
$xml = $source
Else
If Instr($source,"<")=0
; A file name was passed
$xml = LoadXML($source)
Else
; An XML string was passed
$xml = CreateObject("Microsoft.XMLDOM")
$xml.async = false
$=$xml.loadXML($source)
EndIf
EndIf
; End Overloaded Var Sorting

$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

; Begin Overloaded Var Exit Strategy
If VarType($source) = 9
; An object was passed. Since the object was passed by ref, no further
; action necessary.
Else
If Instr($source,"<")=0
; A file name was passed, so we write it out and destory the object
SaveXML($xml, $source)
$xml = 0
Else
; An XML string was passed
; Cannot save the XML string as we have no file name to save to
; so we return it. Since the object was passed by ref, no further
; action necessary.

EndIf
EndIf
; End Overloaded Var Exit Strategy
endfunction



jtokach
(Seasoned Scripter)
2005-03-19 12:24 AM
Re: RFC: ReadXmlString/WriteXmlString

Ok, I'm not updating any one particular post anymore, it's too confusing. Here's all of the latest code that I have. Still a lot of work to be done, and I wont be doing any over the weekend if anyone is bored, but we have a basic working model.

Code:
Break On

$nul=SetOption("ASCII","On")
$nul=SetOption("Explicit","On")

Dim $filename1, $filename2, $filename3
Dim $xml, $

; This is an example by object
$filename1 = "C:\KiXtartByObject.xml"

$xml = LoadXml($filename1)

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

$= WriteXMLAttr($xml, "korg/jim", "Id", 3555)
$= WriteXMLAttr($xml, "korg/jim", "Age", 31)

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

; This is an example by filename
$filename2 = "C:\KiXtartByFileName.xml"

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

$= WriteXMLAttr($filename2, "korg/jim", "Id", 3555)
$= WriteXMLAttr($filename2, "korg/jim", "Age", 31)

? "Jim's age: " ReadXMLAttr($filename2, "korg/jim", "Age")
? "Jose's Number: " ReadXmlValue($filename2, "korg/jose/number")

$xml = 0


; This is an example by XML String
$filename3 = "C:\KiXtartByXMLString.xml"
Dim $strXML,$objXML

$strXML = "<korg><jim><E-mail>jim@@foo.com</E-mail></jim></korg>"
$strXML = WriteXmlValue($strXML, "korg/jim/id",3555)
; Note that after the initial write, the return becomes an object, therefore
; capturing the returns isn't necessary, but doesn't hurt either and is consistent.
$strXML = WriteXmlValue($strXML, "korg/jim/height",6)
$strXML = WriteXmlValue($strXML, "korg/jim/weight",230)
$strXML = WriteXmlValue($strXML, "korg/jim/eyes",2)

$strXML = WriteXMLAttr($strXML, "korg/jim", "Age", 31)
$strXML = WriteXMLAttr($strXML, "korg/jim", "Drink", "Beer")

? "Jim's age: " ReadXMLAttr($strXML, "korg/jim", "Age")


SaveXml($strXML, $filename3)

? "Jim's Drink: " ReadXMLAttr($filename3, "korg/jim", "Age")
$ = RemoveXMLAttr($filename3, "korg/jim", "Age")
? "Jim's Drink: " ReadXMLAttr($filename3, "korg/jim", "Age")

$strXML = 0


exit 1


; CreateXMLElement() - Creates an empty element pair
Function CreateXMLElement()

EndFunction

; EnumXMLAttr() - Enums all attributes of an element
Function EnumXMLAttr()

EndFunction

; EnumXMLElement() - Enums child elements of a given element
Function EnumXMLElement()

EndFunction

;FormatXML() - Formats the output style of an XMLDOM object to the standard
Function FormatXML($objXMLDOM)

;? "V" vartype($objXMLDOM)

Dim $,$strXSL,$objXSL
;Create and Load XSL
; <?xml version="1.0" encoding="UTF-8"?>
; <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
; <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
; <xsl:template match="/ | @* | node()">
; <xsl:copy>
; <xsl:apply-templates select="@* | node()" />
; </xsl:copy>
; </xsl:template>
; </xsl:stylesheet>

$strXSL = "<?xml version=" + chr(34) + "1.0" + chr(34) + " encoding=" +
chr(34) + "UTF-8" + chr(34) + "?>" + @CRLF
$strXSL = $strXSL + "<xsl:stylesheet version=" + chr(34) + "1.0" + chr(34) +
" xmlns:xsl=" + chr(34) + "http://www.w3.org/1999/XSL/Transform" +
chr(34) + ">" + @CRLF
$strXSL = $strXSL + "<xsl:output method=" + chr(34) + "xml" + chr(34) +
" version=" + chr(34) + "1.0" + chr(34) + " encoding=" + chr(34) +
"UTF-8" + chr(34) + " indent=" + chr(34) + "yes" + chr(34) + "/>" + @CRLF
$strXSL = $strXSL + "<xsl:template match=" + chr(34) + "/ | @@* | node()" +
chr(34) + ">" + @CRLF
$strXSL = $strXSL + "<xsl:copy>"+ @CRLF
$strXSL = $strXSL + "<xsl:apply-templates select=" + chr(34) +
"@@* | node()" + chr(34) + " />"+ @CRLF
$strXSL = $strXSL + "</xsl:copy>"+ @CRLF
$strXSL = $strXSL + "</xsl:template>"+ @CRLF
$strXSL = $strXSL + "</xsl:stylesheet>"

;? "XLM Stylesheet: " + @CRLF + $strXSL

$objXSL = CreateObject("Microsoft.XMLDOM")
$objXSL.async = false
$=$objXSL.loadXML($strXSL)

;Transform file
$objXMLDOM.TransformNodeToObject ($objXSL, $objXMLDOM)
$formatXML = $objXMLDOM
EndFunction

;LoadXML() - Load an existing .XML file, instantiate XMLDOM object for use
;regardless of file existance.
Function LoadXML($filename)
dim $, $rootNode, $objNewPI, $strType

$loadXml = CreateObject("Microsoft.XMLDOM")
$loadXml.async = False
$loadXml.preserverwhitespace = True

if not $loadXml
return
endif

$ = $loadXml.Load($filename)
EndFunction

; ReadXMLAttr() - Read a specific attribute of an XML element
Function ReadXMLAttr($source, $Path, $Attr)
Dim $SelectionTag,$AttrName,$,$xml
; *** Begin Overloaded Var Sorting ***
If VarType($source) = 9
; An object was passed
$xml = $source
Else
If Instr($source,"<")=0
; A file name was passed
$xml = LoadXML($source)
Else
; An XML string was passed
$xml = CreateObject("Microsoft.XMLDOM")
$xml.async = false
$=$xml.loadXML($source)
EndIf
EndIf
; *** End Overloaded Var Sorting ***

$SelectionTag = $xml.getElementsByTagName($Path)
$AttrName = $SelectionTag.item(0)
If @ERROR = "-2147352573"
$ReadXMLAttr = ""
Exit @Error
Else
$ReadXMLAttr =$AttrName.getAttribute($Attr)
EndIf

; Begin Overloaded Var Exit Strategy
; None needed
; End Overloaded Var Exit Strategy
EndFunction

;ReadXMLElement() - Reads the value of an XML element
Function ReadXMLValue($source, $key, optional $defaultValue)
Dim $sectionNode,$xml,$

; *** Begin Overloaded Var Sorting ***
If VarType($source) = 9
; An object was passed
$xml = $source
Else
If Instr($source,"<")=0
; A file name was passed
$xml = LoadXML($source)
Else
; An XML string was passed
$xml = CreateObject("Microsoft.XMLDOM")
$xml.async = false
$=$xml.loadXML($source)
EndIf
EndIf

; *** End Overloaded Var Sorting ***

$sectionNode = $xml.SelectSingleNode($key)
If not $sectionNode
$ReadXmlValue = $defaultValue
Else
$ReadXmlValue = $sectionNode.FirstChild.Text
EndIf
EndFunction

; RemoveXMLAttr() - Deletes an XML element attribute
Function RemoveXMLAttr($source, $Path, $attr, optional $id)
Dim $SelectionTag,$AttrTag,$erase,$,$xml

; *** Begin Overloaded Var Sorting ***
If VarType($source) = 9
; An object was passed
$xml = $source
Else
If Instr($source,"<")=0
; A file name was passed
$xml = LoadXML($source)
Else
; An XML string was passed
$xml = CreateObject("Microsoft.XMLDOM")
$xml.async = false
$=$xml.loadXML($source)
EndIf
EndIf
; *** End Overloaded Var Sorting ***

$SelectionTag = $xml.getElementsByTagName($Path)
If $id=""
$id=0
EndIf
$AttrTag = $SelectionTag.item($id)
$erase = $AttrTag.removeAttribute($attr)

; Begin Overloaded Var Exit Strategy
If VarType($source) = 9
; An object was passed.
$RemoveXMLAttr = $xml
Else
If Instr($source,"<")=0

; A file name was passed, so we write it out and destory the object
SaveXML($xml, $source)
Else
; An XML string was passed.
$RemoveXMLAttr = $xml

EndIf
EndIf
; End Overloaded Var Exit Strategy

EndFunction

; RemoveXMLElement() - Deletes an XML element (Recursively?)
Function RemoveXMLElement()

EndFunction

;SaveXML() - Saves an XMLDOM object to a file
; Requires: FormatXML()
Function SaveXML($xml, $filename)
$xml = FormatXML($xml)
$SaveXml = $xml.Save($filename)
EndFunction

Function WriteXMLAttr($source, $Path, $Attr, $Value)
Dim $SelectionTag,$AttrTag,$,$Write,$xml

; *** Begin Overloaded Var Sorting ***
If VarType($source) = 9
; An object was passed
$xml = $source
Else
If Instr($source,"<")=0
; A file name was passed
$xml = LoadXML($source)
Else
; An XML string was passed
$xml = CreateObject("Microsoft.XMLDOM")
$xml.async = false
$=$xml.loadXML($source)
EndIf
EndIf
; *** End Overloaded Var Sorting ***

$SelectionTag = $xml.getElementsByTagName($Path)
$AttrTag = $SelectionTag.item(0)
If @ERROR = "-2147352573"
$ = WriteXmlValue($xml, $path, "")
$SelectionTag = $xml.getElementsByTagName($Path)
$AttrTag = $SelectionTag.item(0)
EndIf
$write = $AttrTag.SetAttribute($Attr,$Value)

; Begin Overloaded Var Exit Strategy
If VarType($source) = 9
; An object was passed.
$WriteXMLAttr = $xml
Else
If Instr($source,"<")=0

; A file name was passed, so we write it out and destory the object
SaveXML($xml, $source)
Else
; An XML string was passed.
$WriteXMLAttr = $xml

EndIf
EndIf
; End Overloaded Var Exit Strategy
EndFunction

; WriteXMLValue() - Writes a value to an XML element
Function WriteXMLValue($source, $path, $value)
dim $, $p, $rootNode, $sectionNode, $parentNode, $childNode, $node, $xml

; *** Begin Overloaded Var Sorting ***
If VarType($source) = 9
; An object was passed
$xml = $source
Else
If Instr($source,"<")=0
; A file name was passed
$xml = LoadXML($source)
Else
; An XML string was passed
$xml = CreateObject("Microsoft.XMLDOM")
$xml.async = false
$=$xml.loadXML($source)
EndIf
EndIf
; *** End Overloaded Var Sorting ***

$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

; Begin Overloaded Var Exit Strategy
If VarType($source) = 9
; An object was passed.
$WriteXMLValue = $xml
Else
If Instr($source,"<")=0

; A file name was passed, so we write it out and destory the object
SaveXML($xml, $source)
Else
; An XML string was passed.
$WriteXMLValue = $xml

EndIf
EndIf
; End Overloaded Var Exit Strategy

endfunction


; ******************************************************************************
; ApplyXSL() - Applies an XSL template. (Much potential here for an expanded
; set, see http://www.devguru.com/Technologies/xslt/quickref/xslt_index.html
Function ApplyXSL()

EndFunction

; FilterXML() - Apply a filter to an XMLDOM object. (Search the db. XSL related.)
Function FilterXML()

EndFunction


Function EnumXML($source)
dim $nodelist,$i
$NodeList = $source.getElementsByTagName("*")
For Each $i In $NodeList
? "Element " +$i.tagName
;? "attributes: " $i.attributes
;? "baseName: " $i.baseName
;? "childNodes: " $i.childNodes
;? "dataType: " $i.dataType
;? "definition: " $i.definition
;? "firstChild: " $i.firstChild.nodeName
;? "lastChild: " $i.lastChild.nodeName
;? "namespaceURI: " $i.namespaceURI
;? "nextSibling: " $i.nextSibling.nodeName
;? "nodeName: " $i.nodeName
;? "nodeType: " $i.nodeType
;? "nodeTypeString: " $i.nodeTypeString
;? "nodeValue: " $i.nodeValue
;? "ownerDocument: " $i.ownerDocument
;? "parentNode: " $i.parentNode.nodeName
;? "parsed: " $i.parsed
;? "prefix: " $i.prefix
;? "previousSibling: " $i.previousSibling.nodeName
;? "specified: " $i.specified
;? "tagName: " $i.tagName
;? "text: " $i.text
? "xml: " $i.xml
?
Next
EndFunction



jtokach
(Seasoned Scripter)
2005-03-23 01:13 AM
Re: RFC: ReadXmlString/WriteXmlString

I think wraps it up, except for the XSL stuff. The ENUM's return collections. Haven't done a decent amount of testing with all of this and error checking is weak.

Code:
Break On
$nul=SetOption("ASCII","On")
$nul=SetOption("Explicit","On")
$nul=SetOption("WrapAtEOL","On")

Dim $filename1, $filename2, $filename3
Dim $xml, $

; This is an example by object
$filename1 = "C:\KiXtartByObject.xml"

$xml = LoadXml($filename1)

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

$= WriteXMLAttr($xml, "korg/jim", "Id", 3555)
$= WriteXMLAttr($xml, "korg/jim", "Age", 31)

$= WriteXMLAttr($xml, "korg/jose", "Id", 4565)
$= WriteXMLAttr($xml, "korg/jose", "Age", 22)

$= WriteXMLAttr($xml, "korg/admins/jim", "Id", 1234)
$= WriteXMLAttr($xml, "korg/admins/jim", "Age", 58)

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

; This is an example by filename
$filename2 = "C:\KiXtartByFileName.xml"

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

$= WriteXMLAttr($filename2, "korg/jim", "Id", 3555)
$= WriteXMLAttr($filename2, "korg/jim", "Age", 31)

? "Jim's age: " ReadXMLAttr($filename2, "korg/jim", "Age")
? "Jose's Number: " ReadXmlValue($filename2, "korg/jose/number")

$xml = 0


; This is an example by XML String
$filename3 = "C:\KiXtartByXMLString.xml"
Dim $strXML,$objXML

$strXML = "<korg><jim><E-mail>jim@@foo.com</E-mail></jim></korg>"
$strXML = WriteXmlValue($strXML, "korg/jim/id",3555)
; Note that after the initial write, the return becomes an object, therefore
; capturing the returns isn't necessary, but doesn't hurt either and is consistent.
$strXML = WriteXmlValue($strXML, "korg/jim/height",6)
$strXML = WriteXmlValue($strXML, "korg/jim/weight",230)
$strXML = WriteXmlValue($strXML, "korg/jim/eyes",2)

$strXML = WriteXMLAttr($strXML, "korg/jim", "Age", 31)
$strXML = WriteXMLAttr($strXML, "korg/jim", "Drink", "Beer")

? "Jim's age: " ReadXMLAttr($strXML, "korg/jim", "Age")
? "Jim's Drink: " ReadXMLAttr($filename3, "korg/jim", "Drink")

SaveXml($strXML, $filename3)

$ = RemoveXMLAttr($filename3, "korg/jim", "Age")
? "Jim's Age: " ReadXMLAttr($filename3, "korg/jim", "Age")

$strXML = 0

; Enumerate elements and attributes
Dim $colE
Dim $colXMLElements
Dim $colAttrs,$colAttr

?? "Enuming All XML Elements"
; Return all elements in the XML file
$colXMLElements = EnumXMLElement($filename1,"*")
For Each $colE In $colXMLElements
? "XML Element Name : " + $colE.TagName
;? "XML Element Value: " + $colE.Text
Next

?? "Enuming Child XML Elements of korg"
; Return all elements in the XML file
$colXMLElements = EnumXMLElement($filename1,"korg/*")
For Each $colE In $colXMLElements
? "XML Element Name : " + $colE.TagName
;? "XML Element Value: " + $colE.Text
Next

?? "Enuming Child XML Elements of korg/shawn"
; Return all elements in the XML file
$colXMLElements = EnumXMLElement($filename1,"korg/shawn/*")
For Each $colE In $colXMLElements
? "XML Element Name : " + $colE.TagName
;? "XML Element Value: " + $colE.Text
Next

?? "Enuming XML Number Elements and their values"
; Return all "number" elements and their value
$colXMLElements = EnumXMLElement($filename1,"number")
For Each $colE In $colXMLElements
? "XML Element Name : " + $colE.TagName
? "XML Element Value: " + $colE.Text
Next

?? "Enuming XML Elements With Attributes and the attribute values (Without EnumXMLAttr)"
; Return all elements that have attributes and enum the attr the long way
$colXMLElements = EnumXMLElement($filename1,"*")
For Each $colE In $colXMLElements
If $colE.Attributes.length > 0
? "XML Element Name : " + $colE.TagName
Dim $strAttr
For Each $strAttr In $colE.Attributes
? " XML Attribute Name : " + $strAttr.Name
? " XML Attribute Value: " + $strAttr.Value
Next
EndIf
Next

?? "Enuming XML Elements With Attributes and the attribute values (With EnumXMLAttr)"
; Return all elements that have attributes and enum the attr the long way
$colXMLElements = EnumXMLElement($filename1,"*")
For Each $colE In $colXMLElements
If $colE.Attributes.length > 0
? "XML Element Name : " + $colE.TagName
$colAttrs = EnumXMLAttr($filename1,$colE.parentNode.nodeName+ "/" + $colE.TagName)
For Each $colAttr In $colAttrs
? "XML Attribute Name : " + $colAttr.Name
? "XML Attribute Value: " + $colAttr.Value
Next
EndIf
Next

?? "Enuming XML Attributes and the attribute values of a specific element (precise path)"
$colAttrs = EnumXMLAttr($filename1,"korg/admins/jim")
For Each $colAttr In $colAttrs
? "XML Attribute Name : " + $colAttr.Name
? "XML Attribute Value: " + $colAttr.Value
Next

?? "Enuming XML Attributes and the attribute values of a specific element (parent only path)"
$colAttrs = EnumXMLAttr($filename1,"admins/jim")
For Each $colAttr In $colAttrs
? "XML Attribute Name : " + $colAttr.Name
? "XML Attribute Value: " + $colAttr.Value
Next

?? "Enuming XML Attributes and the attribute values of the 1st element found called 'Jim'"
$colAttrs = EnumXMLAttr($filename1,"jim")
For Each $colAttr In $colAttrs
? "XML Attribute Name : " + $colAttr.Name
? "XML Attribute Value: " + $colAttr.Value
Next


?? "Creating the forums..."

$=CreateXMLElement($filename1,"korg/forums/starters")
$=CreateXMLElement($filename1,"korg/forums/scripts")
$=CreateXMLElement($filename1,"korg/forums/General Discussion")
$=CreateXMLElement($filename1,"korg/forums/COM")
$=CreateXMLElement($filename1,"korg/forums/UDF")
$=CreateXMLElement($filename1,"korg/forums/UDFs")
$=CreateXMLElement($filename1,"korg/forums/Beta")
$=CreateXMLElement($filename1,"korg/forums/Examples")

?? "Listing forums"
$colXMLElements = EnumXMLElement($filename1,"korg/forums/*")
For Each $colE in $colXMLElements
? "Forum Name : " + $colE.TagName
Next

?? "Deleting error"
$ = RemoveXMLElement($filename1,"forums/UDF")


?? "Listing forums again"
$colXMLElements = EnumXMLElement($filename1,"korg/forums/*")
For Each $colE in $colXMLElements
? "Forum Name : " + $colE.TagName
Next

?? "Deleting all forums"
$ = RemoveXMLElement($filename1,"forums")

?? "Listing forums again"
$colXMLElements = EnumXMLElement($filename1,"korg/forums/*")
For Each $colE in $colXMLElements
? "Forum Name : " + $colE.TagName
Next
exit 1


; CreateXMLElement() - Creates an empty element pair
Function CreateXMLElement($source,$path)
$CreateXMLElement = WriteXMLValue($source,$path,"")
EndFunction

; EnumXMLAttr() - Enums all attributes of an element
Function EnumXMLAttr($source,$path)
Dim $xml,$

; *** Begin Overloaded Var Sorting ***
If VarType($source) = 9
; An object was passed
$xml = $source
Else
If Instr($source,"<")=0
; A file name was passed
$xml = LoadXML($source)
Else
; An XML string was passed
$xml = CreateObject("Microsoft.XMLDOM")
$xml.async = false
$=$xml.loadXML($source)
EndIf
EndIf
; *** End Overloaded Var Sorting ***
Dim $colXMLElements,$colE
$colXMLElements = $xml.getElementsByTagName($path)
If $colXMLElements.item(0).Attributes.length > 0
$EnumXMLAttr = $colXMLElements.item(0).Attributes
EndIf
EndFunction

; EnumXMLElement() - Enums child elements of a given element
Function EnumXMLElement($source,$path)
Dim $xml,$

; *** Begin Overloaded Var Sorting ***
If VarType($source) = 9
; An object was passed
$xml = $source
Else
If Instr($source,"<")=0
; A file name was passed
$xml = LoadXML($source)
Else
; An XML string was passed
$xml = CreateObject("Microsoft.XMLDOM")
$xml.async = false
$=$xml.loadXML($source)
EndIf
EndIf
; *** End Overloaded Var Sorting ***
;Select
; Case Right($path,1)= "/"
; $path = Left($path,Len($path)-1)
; ;? "path "$path
; $EnumXMLElement = $xml.getElementsByTagName($path).Item(0)
; $EnumXMLElement = $EnumXMLElement.ChildNodes
; Case 1
; $EnumXMLElement = $xml.getElementsByTagName($path)
;EndSelect
$EnumXMLElement = $xml.getElementsByTagName($path)
EndFunction

;FormatXML() - Formats the output style of an XMLDOM object to the standard
Function FormatXML($objXMLDOM)

;? "V" vartype($objXMLDOM)

Dim $,$strXSL,$objXSL
;Create and Load XSL
; <?xml version="1.0" encoding="UTF-8"?>
; <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
; <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
; <xsl:template match="/ | @* | node()">
; <xsl:copy>
; <xsl:apply-templates select="@* | node()" />
; </xsl:copy>
; </xsl:template>
; </xsl:stylesheet>

$strXSL = "<?xml version=" + chr(34) + "1.0" + chr(34) + " encoding=" +
chr(34) + "UTF-8" + chr(34) + "?>" + @CRLF
$strXSL = $strXSL + "<xsl:stylesheet version=" + chr(34) + "1.0" + chr(34) +
" xmlns:xsl=" + chr(34) + "http://www.w3.org/1999/XSL/Transform" +
chr(34) + ">" + @CRLF
$strXSL = $strXSL + "<xsl:output method=" + chr(34) + "xml" + chr(34) +
" version=" + chr(34) + "1.0" + chr(34) + " encoding=" + chr(34) +
"UTF-8" + chr(34) + " indent=" + chr(34) + "yes" + chr(34) + "/>" + @CRLF
$strXSL = $strXSL + "<xsl:template match=" + chr(34) + "/ | @@* | node()" +
chr(34) + ">" + @CRLF
$strXSL = $strXSL + "<xsl:copy>"+ @CRLF
$strXSL = $strXSL + "<xsl:apply-templates select=" + chr(34) +
"@@* | node()" + chr(34) + " />"+ @CRLF
$strXSL = $strXSL + "</xsl:copy>"+ @CRLF
$strXSL = $strXSL + "</xsl:template>"+ @CRLF
$strXSL = $strXSL + "</xsl:stylesheet>"

;? "XLM Stylesheet: " + @CRLF + $strXSL

$objXSL = CreateObject("Microsoft.XMLDOM")
$objXSL.async = false
$=$objXSL.loadXML($strXSL)

;Transform file
$objXMLDOM.TransformNodeToObject ($objXSL, $objXMLDOM)
$formatXML = $objXMLDOM
EndFunction

;LoadXML() - Load an existing .XML file, instantiate XMLDOM object for use
;regardless of file existance.
Function LoadXML($filename)
dim $, $rootNode, $objNewPI, $strType

$loadXml = CreateObject("Microsoft.XMLDOM")
$loadXml.async = False
$loadXml.preserverwhitespace = True

if not $loadXml
return
endif

$ = $loadXml.Load($filename)
EndFunction

; ReadXMLAttr() - Read a specific attribute of an XML element
Function ReadXMLAttr($source, $Path, $Attr)
Dim $SelectionTag,$AttrName,$,$xml
; *** Begin Overloaded Var Sorting ***
If VarType($source) = 9
; An object was passed
$xml = $source
Else
If Instr($source,"<")=0
; A file name was passed
$xml = LoadXML($source)
Else
; An XML string was passed
$xml = CreateObject("Microsoft.XMLDOM")
$xml.async = false
$=$xml.loadXML($source)
EndIf
EndIf
; *** End Overloaded Var Sorting ***

$SelectionTag = $xml.getElementsByTagName($Path)
$AttrName = $SelectionTag.item(0)
If @ERROR = "-2147352573"
$ReadXMLAttr = ""
Exit @Error
Else
$ReadXMLAttr =$AttrName.getAttribute($Attr)
EndIf

; Begin Overloaded Var Exit Strategy
; None needed
; End Overloaded Var Exit Strategy
EndFunction

;ReadXMLElement() - Reads the value of an XML element
Function ReadXMLValue($source, $key, optional $defaultValue)
Dim $sectionNode,$xml,$

; *** Begin Overloaded Var Sorting ***
If VarType($source) = 9
; An object was passed
$xml = $source
Else
If Instr($source,"<")=0
; A file name was passed
$xml = LoadXML($source)
Else
; An XML string was passed
$xml = CreateObject("Microsoft.XMLDOM")
$xml.async = false
$=$xml.loadXML($source)
EndIf
EndIf
; *** End Overloaded Var Sorting ***

$sectionNode = $xml.SelectSingleNode($key)
If not $sectionNode
$ReadXmlValue = $defaultValue
Else
$ReadXmlValue = $sectionNode.FirstChild.Text
EndIf
EndFunction

; RemoveXMLAttr() - Deletes an XML element attribute
Function RemoveXMLAttr($source, $Path, $attr, optional $id)
Dim $SelectionTag,$AttrTag,$erase,$,$xml

; *** Begin Overloaded Var Sorting ***
If VarType($source) = 9
; An object was passed
$xml = $source
Else
If Instr($source,"<")=0
; A file name was passed
$xml = LoadXML($source)
Else
; An XML string was passed
$xml = CreateObject("Microsoft.XMLDOM")
$xml.async = false
$=$xml.loadXML($source)
EndIf
EndIf
; *** End Overloaded Var Sorting ***

$SelectionTag = $xml.getElementsByTagName($Path)
If $id=""
$id=0
EndIf
$AttrTag = $SelectionTag.item($id)
$erase = $AttrTag.removeAttribute($attr)

; Begin Overloaded Var Exit Strategy
If VarType($source) = 9
; An object was passed.
$RemoveXMLAttr = $xml
Else
If Instr($source,"<")=0

; A file name was passed, so we write it out and destory the object
SaveXML($xml, $source)
Else
; An XML string was passed.
$RemoveXMLAttr = $xml

EndIf
EndIf
; End Overloaded Var Exit Strategy

EndFunction

; RemoveXMLElement() - Deletes an XML element (Recursively?)
Function RemoveXMLElement($source,$path)
Dim $SelectionTag,$AttrTag,$,$xml

; *** Begin Overloaded Var Sorting ***
If VarType($source) = 9
; An object was passed
$xml = $source
Else
If Instr($source,"<")=0
; A file name was passed
$xml = LoadXML($source)
Else
; An XML string was passed
$xml = CreateObject("Microsoft.XMLDOM")
$xml.async = false
$=$xml.loadXML($source)
EndIf
EndIf
; *** End Overloaded Var Sorting ***

$SelectionTag = $xml.getElementsByTagName($path)
Dim $i

For $i=0 To $SelectionTag.Length - 1
;? "Index "$i
;? "Removing "$SelectionTag.item($i).TagName
;? "Parent " $SelectionTag.item($i).ParentNode.TagName
$=$SelectionTag.item($i).ParentNode.RemoveChild($SelectionTag.item($i))
;? @Serror
Next

; Begin Overloaded Var Exit Strategy
If VarType($source) = 9
; An object was passed.
$RemoveXMLElement = $xml
Else
If Instr($source,"<")=0

; A file name was passed, so we write it out and destory the object
SaveXML($xml, $source)
Else
; An XML string was passed.
$RemoveXMLElement = $xml

EndIf
EndIf
; End Overloaded Var Exit Strategy
EndFunction

;SaveXML() - Saves an XMLDOM object to a file
; Requires: FormatXML()
Function SaveXML($xml, $filename)
$xml = FormatXML($xml)
$SaveXml = $xml.Save($filename)
EndFunction

Function WriteXMLAttr($source, $Path, $Attr, $Value)
Dim $SelectionTag,$AttrTag,$,$Write,$xml

; *** Begin Overloaded Var Sorting ***
If VarType($source) = 9
; An object was passed
$xml = $source
Else
If Instr($source,"<")=0
; A file name was passed
$xml = LoadXML($source)
Else
; An XML string was passed
$xml = CreateObject("Microsoft.XMLDOM")
$xml.async = false
$=$xml.loadXML($source)
EndIf
EndIf
; *** End Overloaded Var Sorting ***

$SelectionTag = $xml.getElementsByTagName($Path)
$AttrTag = $SelectionTag.item(0)
If @ERROR = "-2147352573"
$ = WriteXmlValue($xml, $path, "")
$SelectionTag = $xml.getElementsByTagName($Path)
$AttrTag = $SelectionTag.item(0)
EndIf
$write = $AttrTag.SetAttribute($Attr,$Value)

; Begin Overloaded Var Exit Strategy
If VarType($source) = 9
; An object was passed.
$WriteXMLAttr = $xml
Else
If Instr($source,"<")=0

; A file name was passed, so we write it out and destory the object
SaveXML($xml, $source)
Else
; An XML string was passed.
$WriteXMLAttr = $xml

EndIf
EndIf
; End Overloaded Var Exit Strategy
EndFunction

; WriteXMLValue() - Writes a value to an XML element
Function WriteXMLValue($source, $path, $value)
dim $, $p, $rootNode, $sectionNode, $parentNode, $childNode, $node, $xml

; *** Begin Overloaded Var Sorting ***
If VarType($source) = 9
; An object was passed
$xml = $source
Else
If Instr($source,"<")=0
; A file name was passed
$xml = LoadXML($source)
Else
; An XML string was passed
$xml = CreateObject("Microsoft.XMLDOM")
$xml.async = false
$=$xml.loadXML($source)
EndIf
EndIf
; *** End Overloaded Var Sorting ***

$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

; Begin Overloaded Var Exit Strategy
If VarType($source) = 9
; An object was passed.
$WriteXMLValue = $xml
Else
If Instr($source,"<")=0

; A file name was passed, so we write it out and destory the object
SaveXML($xml, $source)
Else
; An XML string was passed.
$WriteXMLValue = $xml

EndIf
EndIf
; End Overloaded Var Exit Strategy

endfunction


; ******************************************************************************
; ApplyXSL() - Applies an XSL template. (Much potential here for an expanded
; set, see http://www.devguru.com/Technologies/xslt/quickref/xslt_index.html
Function ApplyXSL()

EndFunction

; FilterXML() - Apply a filter to an XMLDOM object. (Search the db. XSL related.)
Function FilterXML()

EndFunction


Function EnumXML($source)
dim $nodelist,$i
$NodeList = $source.getElementsByTagName("*")
For Each $i In $NodeList
? "Element " +$i.tagName
;? "attributes: " $i.attributes
;? "baseName: " $i.baseName
;? "childNodes: " $i.childNodes
;? "dataType: " $i.dataType
;? "definition: " $i.definition
;? "firstChild: " $i.firstChild.nodeName
;? "lastChild: " $i.lastChild.nodeName
;? "namespaceURI: " $i.namespaceURI
;? "nextSibling: " $i.nextSibling.nodeName
;? "nodeName: " $i.nodeName
;? "nodeType: " $i.nodeType
;? "nodeTypeString: " $i.nodeTypeString
;? "nodeValue: " $i.nodeValue
;? "ownerDocument: " $i.ownerDocument
;? "parentNode: " $i.parentNode.nodeName
;? "parsed: " $i.parsed
;? "prefix: " $i.prefix
;? "previousSibling: " $i.previousSibling.nodeName
;? "specified: " $i.specified
;? "tagName: " $i.tagName
;? "text: " $i.text
? "xml: " $i.xml
?
Next
EndFunction



NTDOCAdministrator
(KiX Master)
2005-03-23 08:38 PM
Re: RFC: ReadXmlString/WriteXmlString

Well not exactly in the KiX coding area thought I'd pass along these links for doing, learning XML data with Excel.

Excel 2003 Add-in: XML Tools Add-in
Overview
Learn how to use the Microsoft Office Excel 2003 XML Tools Add-in Version 1.1. With it, you can provide information about a selected cell's XML properties, create XSD files for XML maps, rename the Root and Row elements, or refresh all of the XML maps in a workbook at once.
http://www.microsoft.com/downloads/detai...;displaylang=en

Using the Excel 2003 XML Tools Add-in
James Rivera and Frank Rice show how this new add-in makes working with XML maps, cells, and ranges much easier for developers. (February 2005)
http://msdn.microsoft.com/office/underst...mltooladdin.asp


Part 1: Automating the XML Data Mapping Process in Excel 2003
Learn how to use XML maps to customize Excel as a data input and display system. (March 2005)
http://msdn.microsoft.com/office/underst...ata_mapping.asp

Part 2: Mapping XML from SQL Server to a Single Cell in Excel 2003
In the second of this three-part series, learn how to map well-formed XML from a standard SQL Server query to a single cell in a worksheet. The resulting output is an XML tree with non-repeating elements. (March 2005)
http://msdn.microsoft.com/office/underst..._sql_server.asp

Create XML Mappings in Excel 2003
Walk through common XML tasks in Excel 2003 to learn more about the new XML functionality in Office 2003 Editions. Learn how to add custom schemas, work with XML maps in Excel, and create a series of mappings based on various schemas. (February 2005)
http://msdn.microsoft.com/office/underst...ngscenarios.asp

How Excel 2003 Infers XSDs when Importing XML Data
Review the rules and instances where Excel 2003 infers schema from XML data during import and export. Understand why Excel creates the schemas it does and then learn to modify your own XML data. (February 2005)
http://msdn.microsoft.com/office/underst...nferdetails.asp


jtokach
(Seasoned Scripter)
2005-03-23 10:23 PM
Re: RFC: ReadXmlString/WriteXmlString

Hmmm... The rating on this post went from 5 to 3 three stars... Someone is obviously not happy with something. Please speak your mind rather than let this go down the wrong development path.

Jose
(Seasoned Scripter)
2005-03-25 06:01 AM
Re: RFC: ReadXmlString/WriteXmlString

Hey Jim wonderfull work man!!. Very complete piece of UDF´s.
Sorry I didnt have the time to give you some feedback but I played with it and looks very good. I see you have dealed with RemoveXMLElement() good.


So far..


    LoadXML()
    FormatXML()

    WriteXmlValue()
    CreateXMLElement()
    WriteXMLAttr()

    ReadXMLValue()
    ReadXMLAttr()

    EnumXMLElement()
    EnumXMLAttr()

    RemoveXMLAttr()
    RemoveXMLElement()

    SaveXML()




About XML I have seen resistance notisted at suggestion forum but I think this is kinda normal not specially with XML but for other languajes known as foreings to Kixtart FE Flash,java etc. But it is understandable cause kix makes you love it jealously.

What I really see positive about this thead it that lot have been done since your first suggetion.


Quote:


Not sure if this is practical, but I'll throw it out there. With .XML becoming more and more prevalent, wouldn't it be nice to have functions to manipulate .XML files like the functions we have to manipulate .INI files?





Well...acomplish has been made. A rate is deserved.
Now its time to wait for dear Shawn to speack up about posting as UDF´s. Me going to country side till monday and that makes me happy.

DOC: I dont have Excel 2003 so as to try your links.


jtokach
(Seasoned Scripter)
2005-03-25 07:25 PM
Re: RFC: ReadXmlString/WriteXmlString

Thanks Jose! I was beginning to think this would never see the light of day. Thank Shawn and Chris for renewed spark of interest; add a little elbow grease and voila.

Hope you enjoy your mini-vacation! I'll be writing Use-Case scenarios this weekend for a class I'm taking. That sucks.

Shawn, I suppose we shouldv'e put together a use-case diagram before hammering these out.


ShawnAdministrator
(KiX Supporter)
2005-03-25 07:39 PM
Re: RFC: ReadXmlString/WriteXmlString

use-case diagram ? that anything like flow-charts and gant-charts ? ;0) (idk)

I have been incorporating these XML ideas/strategies into my GRID script (a kinda Excel work-alike) ... the raw native XML functions work very fast - much faster than using INI's ... but ... the UDF's are much slower, even slower then INI's ... has to do with the ReadXmlValue UDF me thinks ... think that one needs a bit of tweaking ...

When done, will give the UDF's a try (again), and apply any lesson's learned to them, hopefully make them much faster than INI's ...

-Shawn


jtokach
(Seasoned Scripter)
2005-03-25 07:51 PM
Re: RFC: ReadXmlString/WriteXmlString

Use-Cases are part of UML somewhere. See:
Link
I'll take a look at ReadXmlValue()


jtokach
(Seasoned Scripter)
2005-03-25 08:40 PM
Re: RFC: ReadXmlString/WriteXmlString

Starting a new thread here.