Jump to content

XML DOM wrapper (COM)


eltorro
 Share

Recommended Posts

Your getting the -1 return value (which is returned on error) because there is not a valid $objDoc. That leads back to _XMLFileOpen().

What is the return value from _XMLFileOpen() ?

Try this in place of what you posted earlier and you'll see what I mean. Are you missing your \ 's in the file name?

Func GetSelection()
    $select = GUICtrlRead($select_list)
     $file = _XMLFileOpen($scriptroot & $select & '.xml')
        if (@error) or ($file = -1) then
             MsgBox(266288,"Error:",_XMLError())
             Exit(1)
        Endif
    $name = _XMLGetValue('/settings/name')
    $author = _XMLGetValue('/settings/author')
     ConsoleWrite($name[1]&@LF)
     ConsoleWrite($author[1]&@LF)
EndFunc
Link to comment
Share on other sites

Hi everyone! I really need some help. I started working with AutoIt a couple of days ago. Several scripts weren't a problem, but now i'm having problems.

Currently i'm working on a inventory project. We use PXserver.com/Winaudit. Winaudit can export to several formats, BUT there's a problem.

The software section is devided in several sub categories. Winaudit discards this information when exporting, except for the XML Export.

I need to change the XML export to an CSV (1st step, importing to SQL is the main goal)

I killed my half finished Autoit script , so i can't place it here.

The XMLfile: LAPZW117.xml

Anyone outthere who can help me ??

Link to comment
Share on other sites

There is a style sheet that goes with the xml. It was not available. Can you post it too.

Link to comment
Share on other sites

I have found that for large 1MB+ xml files, this can be very slow (autoit 3.2.4.9 non-beta).

One solution was to add these functions:

; =======================================================================
; Save and Close XML File
; =======================================================================
Func _XMLFileClose($oIndex=0)
    $objDoc[$oIndex].Save ($strFile[$oIndex])
    $objDoc[$oIndex]=0
    $strFile[$oIndex]=0
EndFunc
; =======================================================================
; Save XML File
; =======================================================================
Func _XMLFileSave($oIndex=0)
    $objDoc[$oIndex].Save ($strFile[$oIndex])
EndFunc

and to comment out all of the $objDoc[$oIndex].Save commands in every OTHER function, so that changes aren't written to the file until you say so. This helps when there are many thousands of changes to be written.

Even after this, it is still rather slow and processor intensive. It seems like AutoIt's Dom (Com?) functionality is slow. If you have any reccommendations on how to speed it up, that would be great.

Link to comment
Share on other sites

For those of you that want to change only a specific attribute value if you have multiple nodes by the same name. Simply specify an index, and only that node's specified attribute will be changed. If you don't specify a index, then only the first found occurrence of the node will have its specific attribute set.

If you specify an index out of range you will still get a return value of 1. I will see about fixing this later.

;===============================================================================
; Function Name:    _XMLSetAttribByIndex
; Description:      Set XML Field based on XPath input from root node and Index. If no index is specified,
;                   then the first found occurance of the XPath will be set.
; Parameters:       $path xml tree path from root node (root/child/child..)
;                   $attrib the attribute to set.
;                   $value the value to give the attribute defaults to ""
;                   $index the index of the node where you want to change the attribute value
; Syntax:           _XMLSetAttribByIndex($path,$attrib,$value,$index)
; Author(s):        Stephen Podhajecki <gehossafats@netmdc.com>, Kaleb D. Tuimala <kaleb_tuimala AT sanityloss DOT com>
; Returns:          1 on success; Returns 1 even if index is out of range. FIXME
;                   on error returns -1 and sets error to 1
;===============================================================================
Func _XMLSetAttribByIndex($strXPath, $strAttrib, $strValue = "", $index = 0)
    If not IsObj($objDoc) then
        _XMLError("No object passed to function _XMLSetAttrib")
        Return SetError(1,8,-1)
    EndIf
    Local $objNodeList, $arrResponse[1], $i
    $objNodeList = $objDoc.selectNodes ($strXPath)
    _DebugWrite(" Node list Length: " & $objNodeList.length)
    While @error = 0 And $objNodeList.length > 0
        $objNodeList.item ($index).SetAttribute ($strAttrib, $strValue)
        $objDoc.save ($strFile)
        Return 1
    WEnd
    _XMLError("Error failed to set attribute for: " & $strXPath & @CRLF)
    SetError(1)
    Return -1
EndFunc   ;==>_XMLSetAttribByIndex
Edited by ktuimala
Link to comment
Share on other sites

I have found that for large 1MB+ xml files, this can be very slow (autoit 3.2.4.9 non-beta).

One solution was to add these functions:

; =======================================================================
; Save and Close XML File
; =======================================================================
Func _XMLFileClose($oIndex=0)
    $objDoc[$oIndex].Save ($strFile[$oIndex])
    $objDoc[$oIndex]=0
    $strFile[$oIndex]=0
EndFunc
; =======================================================================
; Save XML File
; =======================================================================
Func _XMLFileSave($oIndex=0)
    $objDoc[$oIndex].Save ($strFile[$oIndex])
EndFunc

and to comment out all of the $objDoc[$oIndex].Save commands in every OTHER function, so that changes aren't written to the file until you say so. This helps when there are many thousands of changes to be written.

Even after this, it is still rather slow and processor intensive. It seems like AutoIt's Dom (Com?) functionality is slow. If you have any reccommendations on how to speed it up, that would be great.

I am running into this issue as well. Doing what drlava suggested seems to speed it up, but it can take a long time when you are changing thousands of lines or simply creating HUGE xml files.

I am working on a file and directory indexer for shared drives. The information is stored in an XML file. This could lead to an XML file with 10s of 1000s of nodes and 100,000s of attributes. We are talking about a really labor intensive process.

Any ideas on how to speed it up!?!?

Edited by ktuimala
Link to comment
Share on other sites

Any ideas on how to speed it up!?!?

What I ended up doing was manually writing the COM calls instead of using the functions. The functions are great for ease of use and smaller files, but when you get into the larger scope, you should write using the straight COM. In doing so, it can be sped up by leaving off all kinds of things because there are no arrays to test for, and no tests for whether a variable exists nor not. Also, leave out repetitive .selectnodes and .selectsinglenode calls when you are simply adding a bunch of attributes to one node, only one at the beginning is necessary. Same thing for reading a bunch of attributes from one path.. 10 lines per becomes one per attribute.

Still, after all that optimisation, I found that the best thing I could have done is used a real programming language that is compiled (not tokenised and later interpereted) because it seemed it was still 10x slower than a similar compiled program.

Link to comment
Share on other sites

For those of you that want to change only a specific attribute value if you have multiple nodes by the same name.

Can't this already be done by specifying '/yourroot/yournode['&$i&']' for the xpath.. Maybe I misunderstood you but that's what I have been doing.
Link to comment
Share on other sites

Can't this already be done by specifying '/yourroot/yournode['&$i&']' for the xpath.. Maybe I misunderstood you but that's what I have been doing.

That is what I am doing now too. My indexing script now runs in about 5 minutes using that technique instead of 30 or more.
Link to comment
Share on other sites

I am having some trouble reading a very large XML file. The XML file is laid out like this:

<?xml version="1.0" encoding="UTF-8"?>
     <SHARE name="\\usmufn01\smspkgd$">
          <FOLDER name="\">
               <FILE name="unattended_bootdisk.iso" modified="2007/07/25 11:51:23"/>
               <FILE name="version.txt" modified="2005/01/02 19:41:10"/>
          </FOLDER>
          ..........
     </SHARE>

My XML file contains 3923 <FOLDER /> elements. All of them contain a unique folder name. I was using _XMLGetNodeCount("/SHARE/FOLDER") to get the total amount of FOLDER elements. No matter how I slice it, I can only retrieve 589 of the 3923 FOLDER elements.

I took this a step further and communicated to the XML COM element directly and only retrieved 519 of the 3923 FOLDER elements using various count methods provided by the COM. I am connecting to Msxml2.DOMdocument.6.0 for my XML parsing.

To me it seems that the Msxml2.DOMdocument.6.0 has some major limitations in XML processing.

Does anyone have any ideas how to fix this apparent limitation? Is there another XML scripting interface that anyone knows of that would work?

Edited by ktuimala
Link to comment
Share on other sites

<?xml version="1.0" encoding="UTF-8"?>
     <SHARE name="\\usmufn01\smspkgd$">
          <FOLDER name="\">
               <FILE name="unattended_bootdisk.iso" modified="2007/07/25 11:51:23"/>
               <FILE name="version.txt" modified="2005/01/02 19:41:10"/>
          </FOLDER>
          ..........
     </SHARE>
This sucks!! Even if I use XQL to query for an element that I know exists after the 589 FOLDER element mark, I get nothing. However if I use an XQL query on an element that exists 589 or less, the query comes back fine. Again this is with both the XML DOM wrapper and communication directly to the DOM.

How do you deal with XML files over 1MB in size or with elements running in the 1000s?

Edited by ktuimala
Link to comment
Share on other sites

This sucks!! Even if I use XQL to query for an element that I know exists after the 589 FOLDER element mark, I get nothing. However if I use an XQL query on an element that exists 589 or less, the query comes back fine. Again this is with both the XML DOM wrapper and communication directly to the DOM.

How do you deal with XML files over 1MB in size or with elements running in the 1000s?

Try it in vbs and see if it stops 589 element. Post back.

Link to comment
Share on other sites

Try it in vbs and see if it stops 589 element. Post back.

My VBS code:

Dim xmlDoc
Set xmlDoc = CreateObject("Msxml2.DOMdocument.6.0")
Dim c

xmlDoc.Load "C:\Temp\usmufn01.xml"

c = xmlDoc.selectNodes("/SHARE/FOLDER").length

MsgBox c

It stops 2159 elements. This is the correct amount of elements. My previous posts quote 3923 elements. I miscalculated. I accidentally included the </FOLDER> tags in my element count. However, VBS does return the right amount of Elements while AutoIT returns only 589 elements.

So why does VBScript do it properly and not AutoIT? Do you think this is a bug in AutoIT's COM interface?

Link to comment
Share on other sites

My VBS code:

Dim xmlDoc
Set xmlDoc = CreateObject("Msxml2.DOMdocument.6.0")
Dim c

xmlDoc.Load "C:\Temp\usmufn01.xml"

c = xmlDoc.selectNodes("/SHARE/FOLDER").length

MsgBox c

It stops 2159 elements. This is the correct amount of elements. My previous posts quote 3923 elements. I miscalculated. I accidentally included the </FOLDER> tags in my element count. However, VBS does return the right amount of Elements while AutoIT returns only 589 elements.

So why does VBScript do it properly and not AutoIT? Do you think this is a bug in AutoIT's COM interface?

:P

Well, I win the stupid award for the year. In my AutoIT tests of the script, I was still using the _XMLFileOpen() function for my tests, but after using that function I communicated directly with the DOM.

I made a new script to test with:

Dim $xmlDoc = ObjCreate("Msxml2.DOMdocument.6.0")
Dim $c

$xmlDoc.Load("C:\Temp\usmufn01.xml")

$c = $xmlDoc.selectNodes("/SHARE/FOLDER").length

MsgBox(0,"",$c)

This script produces the right results. Eltorro, there seems to be a problem in how _XMLFileOpen() loads the file.

Sorry for doubting the almighty AutoIT!! :)

Do you think this is a bug in AutoIT's COM interface?

Edited by ktuimala
Link to comment
Share on other sites

:P

Well, I win the stupid award for the year. In my AutoIT tests of the script, I was still using the _XMLFileOpen() function for my tests, but after using that function I communicated directly with the DOM.

I made a new script to test with:

Dim $xmlDoc = ObjCreate("Msxml2.DOMdocument.6.0")
Dim $c

$xmlDoc.Load("C:\Temp\usmufn01.xml")

$c = $xmlDoc.selectNodes("/SHARE/FOLDER").length

MsgBox(0,"",$c)

This script produces the right results. Eltorro, there seems to be a problem in how _XMLFileOpen() loads the file.

Sorry for doubting the almighty AutoIT!! :)

Can you pm me your xml?
Link to comment
Share on other sites

This script produces the right results. Eltorro, there seems to be a problem in how _XMLFileOpen() loads the file.

It is a mad world.... and I am at the center of my frustration! :)

I figured out my problem. It was me!! I have so many files laying around that I test with that I misplaced one letter in my file name!! I apologize for wasting all of your time. There is nothing wrong with ELTORRO's code, there is just something wrong with my head!!

Again, my apologies.

Link to comment
Share on other sites

I need a vacation!!

I second that. Third and fourth it too.

Link to comment
Share on other sites

CODE
Example API Request and Response

The following example shows an example XML request and response for the login service. The request is:

<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"

xmlns:SOAPENV=" http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://

www.w3.org/1999/XMLSchema" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance">

<SOAP-ENV:Body>

<login xmlns="http://www.betfair.com/publicapi/BFService/">

<request>

<username>AUserName</username>

<password>APassWord</password>

<productId>22</productId>

<vendorSoftwareId>0</vendorSoftwareId>

<locationId>0</locationId>

</request>

</login>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

The response received is:

<soap:Envelope xmlns:n2="http://www.betfair.com/publicapi/types/" xmlns:soap="http://

schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<soap:Body>

<n:loginResponse xmlns:n="http://www.betfair.com/publicapi/BFService/">

<n:Result xsi:type="n2:LoginResp">

<header xsi:type="n2:APIResponseHeader">

<errorCode xsi:type="n2:APIErrorEnum">OK</errorCode>

<minorErrorCode xsi:nil="1"></minorErrorCode>

<sessionToken xsi:type="xsd:string">r6n+yBbOnm3ret5rkj4ti4Zg<sessionToken>

<timestamp xsi:type="xsd:dateTime">2006-01-06T13:27:58.330Z</timestamp>

</header>

<currency xsi:type="xsd:string">GBP</currency>

<errorCode xsi:type="n2:LoginErrorEnum">OK</errorCode>

<minorErrorCode xsi:nil="1"></minorErrorCode>

<validUntil xsi:type="xsd:dateTime">2006-02-05T00:00:00.000Z</validUntil>

</n:Result>

</n:loginResponse>

</soap:Body>

</soap:Envelope>

In this example, the sessionToken contains the value r6n+yBbOnm3ret5rkj4ti4Zg.

Can anyone help me understand how to make this request and recieve the response if its at all possible, help please anyone.
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...