jtokach
(Seasoned Scripter)
2005-03-25 08:39 PM
RFC: XML UDF's

Started a new topic due to size. Continued from here.

jtokach
(Seasoned Scripter)
2005-03-25 08:45 PM
Re: RFC: XML UDF's

Shawn, we've got a problem. The current setup of WriteXMLvalue, and probably every other UDF doesn't support this type of layout:
Code:
<korg>
<users>
<id>1</id>
<id>2</id>
<id>3</id>
<id>4</id>
<id>5</id>
</users>
</korg>



Back to the drawing board...


LonkeroAdministrator
(KiX Master Guru)
2005-03-25 11:50 PM
Re: RFC: XML UDF's

Quote:

and probably every other UDF doesn't




please be more specific.


jtokach
(Seasoned Scripter)
2005-03-27 12:21 AM
Re: RFC: XML UDF's

All of the XML UDF's we've put together.

ShawnAdministrator
(KiX Supporter)
2005-03-28 08:07 PM
Re: RFC: XML UDF's

Jim,

I'm still working muchly with the "raw" XML functions. Lessons learned so far:

1) Reading Attributes of a node is much, much faster than reading child-elements (of the node) containing the same information... for example reading this:

Code:

<node1>
<data1>1</data1>
<data2>2</data2>
</node1>



is much slower then reading this:

Code:

<node1 data1="1" data2="2">
</node1>



Probably this has more to do with how one would "design" their schema, versus the UDF's themselves - just an observation.

-Shawn


jtokach
(Seasoned Scripter)
2005-03-28 08:18 PM
Re: RFC: XML UDF's

Indeed, that makes sense; less parsing, more direct. Also agreed, more for planning purposes than anything else. I'll see what I can up with regarding the issue above.

ShawnAdministrator
(KiX Supporter)
2005-03-28 08:41 PM
Re: RFC: XML UDF's

I complained earlier in another thread - that it seemed a "waste" to have create an element as a child of the entire document, then later to have to add the element as a child of some other element ....

Lesson learned number two:

This isn't necessarily a bad thing - I learned that it is advantageous to be able to create an element, and to populate it with attributes and sub-elements - then to be able to later make the determination whether to actually add it as a child.

This ability really helped me in my GRID script - i was able to skip-over having to save CELL elements that only contained default settings (therefore don't need to be saved) - this speeds up the "loading" of the grid later on.

-Shawn


ShawnAdministrator
(KiX Supporter)
2005-03-28 08:57 PM
Re: RFC: XML UDF's

Having a "messy" XML file isn't necessarily a "bad thing", if one has a half-decent XML editor/viewer to edit/view with ;0)

Lesson learned number #3 - messy XML aint the end of the world ... here's a sample of my GRID (spread-sheet) like schema so far...

<Grid RowCount="11" ColumnCount="3" AllowSorting="-1" AlternatingBackColor="-1" BackColor="16777215" ColumnHeaderStyle="2" CurrentColumnIndex="0" CurrentRowIndex="0" FontName="Verdana" FontSize="8" ForeColor="0" FullRowSelect="0" GridColor="8421504" GridLines="3" MultiSelect="0" ReadOnly="0" SingleClickEdit="0">
- <Columns>
<Column.0 Index="0" Alignment="-1" AllowSorting="-1" BackColor="-1" CellType="-1" ForeColor="-1" Format="" HeaderText="CategoryID" ImageIndex="-1" MinimumWidth="15" Name="CategoryID" ReadOnly="0" Resizable="-1" Width="100" ValueType="5" />
<Column.1 Index="1" Alignment="-1" AllowSorting="-1" BackColor="-1" CellType="-1" ForeColor="-1" Format="" HeaderText="CategoryName" ImageIndex="-1" MinimumWidth="15" Name="CategoryName" ReadOnly="0" Resizable="-1" Width="100" ValueType="8" />
<Column.2 Index="2" Alignment="-1" AllowSorting="-1" BackColor="-1" CellType="-1" ForeColor="-1" Format="" HeaderText="Description" ImageIndex="-1" MinimumWidth="15" Name="Description" ReadOnly="0" Resizable="-1" Width="100" ValueType="8" />
</Columns>
- <Cells>
<Cell.0.0 Value="1" RowIndex="0" ColumnIndex="0" />
<Cell.0.1 Value="Beverages" RowIndex="0" ColumnIndex="1" />
<Cell.0.2 Value="Soft drinks, coffees, teas, beers, and ales" RowIndex="0" ColumnIndex="2" />
<Cell.1.0 Value="2" RowIndex="1" ColumnIndex="0" />
<Cell.1.1 Value="Condiments" RowIndex="1" ColumnIndex="1" />
<Cell.1.2 Value="Sweet and savory sauces, relishes, spreads, and seasonings" RowIndex="1" ColumnIndex="2" />
<Cell.2.0 Value="3" RowIndex="2" ColumnIndex="0" />
<Cell.2.1 Value="Confections" RowIndex="2" ColumnIndex="1" />
<Cell.2.2 Value="Desserts, candies, and sweet breads" RowIndex="2" ColumnIndex="2" />
<Cell.3.0 Value="4" RowIndex="3" ColumnIndex="0" />
<Cell.3.1 Value="Dairy Products" RowIndex="3" ColumnIndex="1" />
<Cell.3.2 Value="Cheeses" RowIndex="3" ColumnIndex="2" />
<Cell.4.0 Value="5" RowIndex="4" ColumnIndex="0" />
<Cell.4.1 Value="Grains/Cereals" RowIndex="4" ColumnIndex="1" />
<Cell.4.2 Value="Breads, crackers, pasta, and cereal" RowIndex="4" ColumnIndex="2" />
<Cell.5.0 Value="6" RowIndex="5" ColumnIndex="0" />
<Cell.5.1 Value="Meat/Poultry" RowIndex="5" ColumnIndex="1" />
<Cell.5.2 Value="Prepared meats" RowIndex="5" ColumnIndex="2" />
<Cell.6.0 Value="7" RowIndex="6" ColumnIndex="0" />
<Cell.6.1 Value="Produce" RowIndex="6" ColumnIndex="1" />
<Cell.6.2 Value="Dried fruit and bean curd" RowIndex="6" ColumnIndex="2" />
<Cell.7.0 Value="8" RowIndex="7" ColumnIndex="0" />
<Cell.7.1 Value="Seafood" RowIndex="7" ColumnIndex="1" />
<Cell.7.2 Value="Seaweed and fish" RowIndex="7" ColumnIndex="2" />
<Cell.8.0 Value="13" RowIndex="8" ColumnIndex="0" />
<Cell.8.1 Value="ssss" RowIndex="8" ColumnIndex="1" />
<Cell.9.0 Value="14" RowIndex="9" ColumnIndex="0" />
<Cell.9.1 Value="xxxx" RowIndex="9" ColumnIndex="1" />
<Cell.10.0 Value="9" RowIndex="10" ColumnIndex="0" />
<Cell.10.1 Value="Shawn" RowIndex="10" ColumnIndex="1" />
</Cells>
</Grid>


Jose
(Seasoned Scripter)
2005-03-29 10:17 PM
Re: RFC: XML UDF's

Shawn just to add to this story I have seen on a simple google search that attributes are known to be fast but there is reason why.

Reference

Quote:


The primary key in an XML structure, the one used to identify specific objects, has a requirement that it be unique. Typically for XML structures, this uniqueness will come in the form of an ID of some sort. For the sample characters document, the ID is actually an attribute called "id" attached to the node. Because most parsers are able to parse attributes faster than elements and because an ID is less a describing property of the object and more a name for that object, you should keep IDs and ID references as attributes within your document structure for best efficiency.










But using attributes as child element has its problems too.

Quote:


Some of the problems with using attributes are:

* attributes cannot contain multiple values (child elements can)
* attributes are not easily expandable (for future changes)
* attributes cannot describe structures (child elements can)
* attributes are more difficult to manipulate by program code
* attribute values are not easy to test against a Document Type Definition (DTD) - which is used to define the legal elements of an XML document.

If you use attributes as containers for data, you end up with documents that are difficult to read and maintain. Try to use elements to describe data. Use attributes only to provide information that is not relevant to the data.





Jose
(Seasoned Scripter)
2005-04-21 08:11 AM
Re: RFC: XML UDF's

I have been doing some XML and noticed that in WriteXMLValue($source, $path, $value) any child included in the path cannot start with a number, otherwise you get error.
Example:
Code:

$= WriteXmlValue($xml, "korg/shawn/1_number", 119)



Jose
(Seasoned Scripter)
2005-04-26 01:49 AM
Re: RFC: XML UDF's

Shawn, Jim:
I find these new UDF´s very intresting and usefull but still there is something I cannot do with them.

It is ideal and for a better xml structure to store data on an XML file using the attribute as a table Id like this:
Code:
  
<messages>
<note id="p501">
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
<note id="p502">
<to>Jani</to>
<from>Tove</from>
<heading>Re: Reminder</heading>
<body>I will not!</body>
</note>
</messages>


I found difficulties when you need to update an elemets that hangs from a a root value referenced with an attribute, FE (case above). I want to modify the body when id="p502".

If we can solve this I think there is gonna be little left to manipulate any XML with Kix.

Thanks boys.


BTW:
Looks like 'without UBBcode/HTML' combo is not working.....mnn......yes it is, after I posted this modification...weird.


ShawnAdministrator
(KiX Supporter)
2005-04-26 02:16 AM
Re: RFC: XML UDF's

Jose/Jim.

I have been playing much with the XMLDOM object model and wrote a little script that helped me "explore" the model. Its actually quite instructive to poke around XMLDOM and see (visually) just how "strange" it is.

If you want to check it out (the work-in-progress), I posted it here:

XML Workshop

You need the latest kixforms dev build to run this, here:

Kixforms Development Build

Would love to get your feedback/observations on this.

-Shawn


Jose
(Seasoned Scripter)
2005-04-26 07:19 AM
Re: RFC: XML UDF's

Well Shawn you have really done some difference here. Very nice man!! .
I will give a try tomorrow at and post some feedback.

About what I have asked above about the element uptade according to the attr (similar to id of table), now that Shawn is an XMLDOM expert he had fixed a code that does the task wich can perfectly fit to a new UDF.
Here is the code:
Code:
  
<?xml version="1.0" encoding="UTF-8"?>
<messages>
<note id="p501">
<to>Jani</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Dont forget me this weekend!</body>
</note>
<note id="p502">
<to>Jani</to>
<from>Tove</from>
<heading>How are you</heading>
<body>Gimme a call Tovy!!</body>
</note>
<note id="p503">
<to>Shawn</to>
<from>Joser</from>
<heading>Shawn you.....</heading>
<body>.....are a wonderfull person</body>
</note>
</messages>


In wich case if I want to update <to> value of id="p501" attr would be something like this. It is rought script wet.
Code:
  
UpdateFromAttribute('id', 'p501', 'body', 'Dont forget me this weekend!...please')


Code:
  
Function UpdateFromAttribute($Attr, $AttrValue, $Path, $PathValue)
For Each $note In $xml.documentelement.childnodes
If $note.getattribute($Attr) = $AttrValue
$heading = $note.selectsinglenode($Path)
$heading.text = $PathValue
EndIf
Next
EndFunction



jtokach
(Seasoned Scripter)
2005-04-26 06:15 PM
Re: RFC: XML UDF's

Jose,

There are several problems with the current UDF's which I didn't realize until afterwards; my second post in this thread being the main problem. I really haven't had time to come back to this and probably wont for a few weeks. Of course, if Shawn has developed a better model, we can choose to emulate it in Kix so that they are independant of the kixforms.dll. It certainly wont be anywhere near as fast though but at least they'll jive.


ShawnAdministrator
(KiX Supporter)
2005-04-26 06:39 PM
Re: RFC: XML UDF's

I didn't devise a new model, just wrote a kixscript that allows one to "explore" the existing XMLDOM model. It presents a TreeView on the left, with all the nodes as they are presented by xmldom. On the right, one can see all the xmldom properties. There is another Tab for xml view.

-Shawn


jtokach
(Seasoned Scripter)
2005-04-26 06:49 PM
Re: RFC: XML UDF's

Ah, well then, these still need a major overhaul to cope with post #2 and jose's attribute thingys. We jumped into this without enough forethought. The specifications need to be changed to handle the above or a different model needs adoption. I think we have enough info and made enough mistakes to develop a solid set of UDF's here on out. Perhaps we can also consider performance this time through, or leave it for version 2.

Jose
(Seasoned Scripter)
2005-04-26 07:01 PM
Re: RFC: XML UDF's

But Jim those "several problems" arent that bad. I have been using these udf's normally, besides there where none to use before so that is good. I say to go ahead shoot the UDF's and make corrections on the fly.

jtokach
(Seasoned Scripter)
2005-04-26 07:06 PM
Re: RFC: XML UDF's

For me, the post #2 problem is a show stopper. It needs to be fixed/incorporated which means a major overhaul to the UDF's specifications.

Jose
(Seasoned Scripter)
2005-04-26 07:24 PM
Re: RFC: XML UDF's

Pardon my ignorance Jim, can you explain me the problem #2 with a sample for me to understand? I cannot find your reference.

ShawnAdministrator
(KiX Supporter)
2005-04-26 07:32 PM
Re: RFC: XML UDF's

Me too - Can we have a summary of issues ?

jtokach
(Seasoned Scripter)
2005-04-26 07:35 PM
Re: RFC: XML UDF's

The second post in this thread explains it. post #2

This format is standard and needs support. Given our setup, we have no facility to write or read that format.


ShawnAdministrator
(KiX Supporter)
2005-04-26 07:44 PM
Re: RFC: XML UDF's

So based on this link, we could create a Kixtart function called FormatXML(), is that where your heading ?

-Shawn


jtokach
(Seasoned Scripter)
2005-04-26 07:48 PM
Re: RFC: XML UDF's

Nope, we already have a formatXML function to format via XSL. What I'm saying is, try to create that XML from the current UDF's we have. It's not possible, b/c we have no way to reference the first <id> tag from the second, third or fourth.

ShawnAdministrator
(KiX Supporter)
2005-04-26 07:53 PM
Re: RFC: XML UDF's

If its not possible, then why worry about it ? ;0)

Jose
(Seasoned Scripter)
2005-04-26 07:54 PM
Re: RFC: XML UDF's

I get your point, but that shoudnt be done with an Attribute like this <id number=1> FE to identify it like I posted above?.
Code:
  
<korg>
<users>
<id n=1>1</id>
<id n=2>2</id>
<id n=3>3</id>
<id n=4>4</id>
<id n=5>5</id>
</users>
</korg>





BTW have you seen such format used that much?


jtokach
(Seasoned Scripter)
2005-04-26 08:19 PM
Re: RFC: XML UDF's

Jose, that format is quite standard. I've seen it everywhere. In fact, it seems to be pretty dominant. There doesn't need to attributes is what my point is and many existing XML's may not have them so we need to address it. Example 1 at DevGuru

Example 2 (XML to SQL - This is my end goal)


Jose
(Seasoned Scripter)
2005-04-27 01:39 AM
Re: RFC: XML UDF's

I see Jim, you are right about its importance but I am of the thought that there is plenty to do with what is done by now, sure we will get on with it. Dont you forget there is a community behind us ready to bring a solution after a particular need .

jtokach
(Seasoned Scripter)
2005-04-27 04:34 PM
Re: RFC: XML UDF's

Jose, I'd love to start using these now, but I think once we get into it, the specifications will all change which will force you to go back to all of your old scripts and change them as well...

Jose
(Seasoned Scripter)
2005-04-30 03:10 AM
Re: RFC: XML UDF's

Well I guess there is gonna have to be some more fridge for them .

jtokach
(Seasoned Scripter)
2005-05-06 10:14 PM
Re: RFC: XML UDF's

Jose, you win. I started looking into this, and let me tell you what a massive pain in the ass it is. I'm thinking that the attributes are going to be the way to go. We'll just need to claim "limited" XML support.

jtokach
(Seasoned Scripter)
2005-05-10 08:37 PM
Re: RFC: XML UDF's

Ok, pain in the ass or not, I couldn't find any way around this, so I spent some time and got it working.

Also note that I changed all of the function names so they all match up and can be sorted and searched on easier. Here's all of the latest code and an example that creates an XML file, parses it and writes some SQL based on it.

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

Dim $fileXMLdata
Dim $xml, $

Dim $SQL,$iSQL,$uSQL,$DBServer,$DBName,$DBType,$DSN,$DBUsername,$DBPassword
Dim $TableName,$PKey,$SKey,$FieldNames,$FieldData
Dim $colXMLElements,$colE
Dim $arySQL[0]


$fileXMLdata = "db.xml"


; Delete an existing XML file as the append functions will append to an
; existing file
If Exist($fileXMLdata)
Del $fileXMLdata
EndIf

; Create the XML file using the new append functions
$= XMLAppendElement($fileXMLdata, "Database", "")
$= XMLAppendAttr($fileXMLdata, "Database", "Server", "MyServer")
$= XMLAppendAttr($fileXMLdata, "Database", "Name", "MyDB")
$= XMLAppendAttr($fileXMLdata, "Database", "Type", "MySQL")
$= XMLAppendAttr($fileXMLdata, "Database", "Username", "root")
$= XMLAppendAttr($fileXMLdata, "Database", "Password", "MyPass")

$= XMLAppendElement($fileXMLdata, "Database/Table", "")
$= XMLAppendAttr($fileXMLdata, "Database/Table", "Name", "Computers")
$= XMLAppendAttr($fileXMLdata, "Database/Table", "PrimaryKey", "Hostname")
$= XMLAppendAttr($fileXMLdata, "Database/Table", "SecondaryKey", "")

$= XMLAppendElement($fileXMLdata, "Database/Table/Record", "")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/Hostname", "COMPUTER01")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/LastUpdated", @Date + " " + @Time)
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/HardwareMake", "Dell Computer Corporation")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/HardwareModel", "OptiPlex GX200")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/HardwareSN", "123572256132345")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/HardwareBiosVer", "DELL - 8|Phoenix ROM BIOS PLUS Version 1.10 A03|")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/HardwareBiosDate", "02/28/01")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/HardwareCPU", @CPU)

$= XMLAppendElement($fileXMLdata, "Database/Table", "")
$= XMLAppendAttr($fileXMLdata, "Database/Table", "Name", "Hotfixes")
$= XMLAppendAttr($fileXMLdata, "Database/Table", "PrimaryKey", "Hostname")
$= XMLAppendAttr($fileXMLdata, "Database/Table", "SecondaryKey", "Hotfix")

$= XMLAppendElement($fileXMLdata, "Database/Table/Record", "")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/Hostname", "COMPUTER01")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/LastUpdated", @Date + " " + @Time)
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/Hotfix", "MS04_011")

$= XMLAppendElement($fileXMLdata, "Database/Table/Record", "")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/Hostname", "COMPUTER01")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/LastUpdated", @Date + " " + @Time)
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/Hotfix", "MS04_012")

$= XMLAppendElement($fileXMLdata, "Database/Table/Record", "")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/Hostname", "COMPUTER01")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/LastUpdated", @Date + " " + @Time)
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/Hotfix", "MS04_013")

$= XMLAppendElement($fileXMLdata, "Database/Table/Record", "")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/Hostname", "COMPUTER01")
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/LastUpdated", @Date + " " + @Time)
$= XMLAppendElement($fileXMLdata, "Database/Table/Record/Hotfix", "MS04_014")

$xml = 0


; Enumerate all of the elements in the XML file into a collection of objects
$colXMLElements = XMLEnumElements($fileXMLdata,"*")

; Iterate the collection, create SQL statments with the data, add each statement
; to an array
For Each $colE In $colXMLElements
Select
Case $colE.TagName = "Database"
$DBServer = $colE.getAttribute("Server")
$DBName = $colE.getAttribute("Name")
$DBType = $colE.getAttribute("Type")
$DBUsername = $colE.getAttribute("Username")
$DBPassword = $colE.getAttribute("Password")

If $DBType = "MySQL"
$DSN="DRIVER={MySQL ODBC 3.51 Driver};SERVER="+$DBServer+";DATABASE="+$DBName+";UID="+$DBUsername+";PWD="+$DBPassword
EndIf

Case $colE.TagName = "Table"
$TableName = $colE.getAttribute("Name")
$PKey = $colE.getAttribute("PrimaryKey")
$SKey = $colE.getAttribute("SecondaryKey")

Case $colE.TagName = "Record"
If $FieldNames <> ""
;$uSQL = "UPDATE " + $TableName + " SET " + $element + " WHERE " + $KeyName + " = '" + $KeyData + "'"
$iSQL = "INSERT INTO " + $TableName + "(" + $FieldNames + ") VALUES (" + $FieldData + ")"

$arySQL[ubound($arySQL)]=$iSQL
Redim Preserve $arySQL[ubound($arySQL)+1]
EndIf
$SQL = ""
$FieldNames = ""
$FieldData = ""

Case 1
; Must be a record for the current table.
If $FieldNames = ""
$FieldNames = $colE.TagName
$FieldData = "'" + $colE.Text + "'"
Else
$FieldNames = $FieldNames + "," + $colE.TagName
$FieldData = $FieldData + ",'" + $colE.Text + "'"
EndIf
EndSelect
Next
; Adds the remaining parsed data to the array
$iSQL = "INSERT INTO " + $TableName + "(" + $FieldNames + ") VALUES (" + $FieldData + ")"
$arySQL[ubound($arySQL)]=$iSQL

; Print the data to the console
? "DSN: " + $DSN
?
Dim $k
For Each $k In $arySQL
? "iSQL: " + $k
Next


Exit 1






Function XMLAppendAttr($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 = XMLLoad($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($SelectionTag.length-1)
If @ERROR = "-2147352573"
$ = XMLWriteValue($xml, $path, "")
$SelectionTag = $xml.getElementsByTagName($Path)
$AttrTag = $SelectionTag.item($SelectionTag.length-1)
EndIf
$write = $AttrTag.SetAttribute($Attr,$Value)

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

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

EndIf
EndIf
; End Overloaded Var Exit Strategy
EndFunction

; XMLAppendElement() - Writes a value to an XML element
Function XMLAppendElement($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
;? "filename"
$xml = XMLLoad($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
; The node does not exist
$parentNode = $xml

for each $node in split($path,"/")
Dim $colXMLElements
$p = $p + $node

$colXMLElements = $xml.getElementsByTagName($p)
If $colXMLElements.length > 1
$sectionNode = $colXMLElements.Item($colXMLElements.length-1)
Else
$sectionNode = $xml.SelectSingleNode($p)
EndIf

if not $sectionNode
$sectionNode = $xml.CreateElement($node)
$parentNode = $parentNode.AppendChild($sectionNode)
else
$parentNode = $sectionNode
endif
$p = $p + "/"
next
Else
Dim $colXMLElements
Dim $aryNodes
Dim $ParentNodeName
;? "Does exist, appending"
;The node does exist, get the count of each
$aryNodes = split($path,"/")
$Node = $aryNodes[ubound($aryNodes)]
;? "Node "$node
$ParentNodeName = Join($aryNodes,"/",Ubound($aryNodes))
;? "PN " $parentnodeName

$colXMLElements = $xml.getElementsByTagName($ParentNodeName)
If $colXMLElements.length > 1
;? "more than one"
;? "c " $colXMLElements.length
;? "item "$colXMLElements.Item($colXMLElements.length-1).TagName
$ParentNode = $colXMLElements.Item($colXMLElements.length-1)
;$ParentNode = $xml.SelectSingleNode($parentnodeName)
Else
;? "not more than one"
;$sectionNode = $xml.SelectSingleNode($parentnode)
;? "SN " $sectionNode.TagName
$ParentNode = $xml.SelectSingleNode($parentnodeName)
EndIf
$sectionNode = $xml.CreateElement($node)
$parentNode = $parentNode.AppendChild($sectionNode)
EndIf

; wrtie val to current section
If $sectionNode
$sectionNode.Text = $value
EndIf


; Begin Overloaded Var Exit Strategy
If VarType($source) = 9
; An object was passed.
$XMLAppendElement = $xml
Else
If Instr($source,"<")=0
;? "Save"
; A file name was passed, so we write it out and destory the object
XMLSave($xml, $source)
;? "save2"
Else
; An XML string was passed.
$XMLAppendElement = $xml

EndIf
EndIf
; End Overloaded Var Exit Strategy

endfunction


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

; XMLEnumAttr() - Enums all attributes of an element
Function XMLEnumAttr($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 = XMLLoad($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
$XMLEnumAttr = $colXMLElements.item(0).Attributes
EndIf
EndFunction

; XMLEnumElements() - Enums child elements of a given element
Function XMLEnumElements($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 = XMLLoad($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
; $XMLEnumElements = $xml.getElementsByTagName($path).Item(0)
; $XMLEnumElements = $XMLEnumElements.ChildNodes
; Case 1
; $XMLEnumElements = $xml.getElementsByTagName($path)
;EndSelect
$XMLEnumElements = $xml.getElementsByTagName($path)
EndFunction

;XMLFormatOutput() - Formats the output style of an XMLDOM object to the standard
Function XMLFormatOutput($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)
$XMLFormatOutput = $objXMLDOM
EndFunction

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

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

if not $XMLLoad
return
endif

$ = $XMLLoad.Load($filename)
EndFunction

; XMLReadAttr() - Read a specific attribute of an XML element
Function XMLReadAttr($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 = XMLLoad($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"
$XMLReadAttr = ""
Exit @Error
Else
$XMLReadAttr =$AttrName.getAttribute($Attr)
EndIf

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

;XMLReadValue() - Reads the value of an XML element
Function XMLReadValue($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 = XMLLoad($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
$XMLReadValue = $defaultValue
Else
$XMLReadValue = $sectionNode.FirstChild.Text
EndIf
EndFunction

; XMLRemoveAttr() - Deletes an XML element attribute
Function XMLRemoveAttr($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 = XMLLoad($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.
$XMLRemoveAttr = $xml
Else
If Instr($source,"<")=0

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

EndIf
EndIf
; End Overloaded Var Exit Strategy

EndFunction

; XMLRemoveElement() - Deletes an XML element (Recursively?)
Function XMLRemoveElement($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 = XMLLoad($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.
$XMLRemoveElement = $xml
Else
If Instr($source,"<")=0

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

EndIf
EndIf
; End Overloaded Var Exit Strategy
EndFunction

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

Function XMLWriteAttr($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 = XMLLoad($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"
$ = XMLWriteValue($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.
$XMLWriteAttr = $xml
Else
If Instr($source,"<")=0

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

EndIf
EndIf
; End Overloaded Var Exit Strategy
EndFunction

; XMLWriteValue() - Writes a value to an XML element
Function XMLWriteValue($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 = XMLLoad($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.
$XMLWriteValue = $xml
Else
If Instr($source,"<")=0

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

EndIf
EndIf
; End Overloaded Var Exit Strategy

endfunction


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

EndFunction

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

EndFunction


Function XMLEnum($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
$XMLEnum = $NodeList
EndFunction



Jose
(Seasoned Scripter)
2005-05-12 06:28 AM
Re: RFC: XML UDF's

Intresting concept man!.

Jim I have tryed your code but I get an error here in XMLFormatOutput($objXMLDOM) at this point.
Code:
  
$strXSL = " chr(34) + "UTF-8" + chr(34) + "?>" + @CRLF


Replaced with this and worked out.
Code:
  
$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>"



Check it Jim please.


jtokach
(Seasoned Scripter)
2005-05-12 04:45 PM
Re: RFC: XML UDF's

Jose, this crappy board upgrade keeps dropping XML tags... I'll update the previous code and if there are no further items to work on, I think we're ready to package these up for the UDF forum.

jtokach
(Seasoned Scripter)
2005-05-12 04:51 PM
Re: RFC: XML UDF's

Regarding the missing code, the trick is to:
1. make the orignal post
2. notice missing XML/HTML tags
3. edit the post, you'll see that the code is actually there
4. save the post again and voila, it magically appears

This is a bug, which is currently working to our advantage. One of the MODS should report to Henri and/or Infopop.

Anyway, the code should work now.


NTDOCAdministrator
(KiX Master)
2005-05-26 10:45 PM
Re: RFC: XML UDF's

Just FYI if interested - not really of much help internally though with KiXtart.

Improve XML Processing with VTD-XML
 


NTDOCAdministrator
(KiX Master)
2005-06-05 12:36 AM
Re: RFC: XML UDF's

Jim,

Just ran across this in the WMI materials. Here is an example. Shawn has a mini reader that read the output just fine. Not solid code, but example works.

 
SWbemObjectEx.GetText_
The GetText_ method of the SWbemObjectEx object returns an XML representation of an object or instance. The text file is formatted in the XML format specified as shown in WbemObjectTextFormatEnum.

WbemObjectTextFormatEnum

Code:
Break On
Dim $SO,$Pause
$SO=SetOption('Explicit','On')
$SO=SetOption('NoVarsInStrings','On')
$SO=SetOption('WrapAtEOL','Off')
 
Dim $MyBIOSInfo,$W
$MyBIOSInfo = GetBIOSInfo()
If Exist('C:\TEMP\TEST.XML') DEL 'C:\TEMP\TEST.XML' EndIf
$W = Open(1, 'C:\TEMP\TEST.XML',5)
$W = WriteLine(1,$MyBIOSInfo[0]+@CRLF)
$W = Close(1)
 
Function GetBIOSInfo()
Dim $Computer, $WMIService, $BIOSItems
Dim $Item, $SerialNumber, $Manufacturer, $BIOSArray[1]
Dim $XMLDtd
$XMLDtd = 2
$Computer = "."
$WMIService = GetObject("winmgmts:\\" + $Computer + "\root\cimv2")
$BIOSItems = $WMIService.ExecQuery("Select * from Win32_BIOS",,48)
For Each $Item in $BIOSItems
$SerialNumber = $Item.GetText_($XMLDtd)
Next
$BIOSArray[0]=$SerialNumber
$GetBIOSInfo=$BIOSArray
EndFunction


 


jtokach
(Seasoned Scripter)
2005-06-10 08:08 PM
Re: RFC: XML UDF's

This is interesting. I can't wait to get a chance to play with it.

NTDOCAdministrator
(KiX Master)
2006-02-27 09:17 AM
Re: RFC: XML UDF's

Not sure if you've seen this or not as I've not reviewed all the code you've written so far.


How to navigate XML with the XPathNavigator class by using Visual Basic
http://support.microsoft.com/kb/301111/en-us