Jump to content

XML DOM wrapper (COM)


eltorro
 Share

Recommended Posts

If you look at the code for _XMLFileOpen you will see that $objdoc is deleted upon parse failure, therefore trying to access it will fail.

You can change the call to _XMLError below to include the line number easily. Then you just call _XMLError() after _XMLFileOpen and it will show the line number.

Here is the code:

If $objDoc.parseError.errorCode <> 0 Then
        _XMLError("Error opening specified file: " & $strXMLFile & @CRLF & $objDoc.parseError.reason)
        SetError($objDoc.parseError.errorCode)
        $objDoc = 0
        Return -1
    EndIf
Link to comment
Share on other sites

I have a little problem with the wrapper...and it might just be a bug in the component. I have the following XML file. After calline DeleteNode() / CreateNode() multiple times, blank lines start appearing in the XML file. Try the example and see all the blank lines. Any idea if there's a way to fix this?

Example XML -

<?xml version="1.0"?>

<WMBasicEdit >
    <Attributes >
    <WMENC_QWORD Name="WM/ASFPacketCount" Value="6193" />
    <WMENC_QWORD Name="WM/ASFSecurityObjectsSize" Value="0" />
    <WMENC_BLOB Name="WM/StreamTypeInfo" >
    <![CDATA[6175647300001000800000aa00389b711c00000061010100803e0000d0070000800210000a00002200002e0080070000

]]>
    </WMENC_BLOB>

    <WMENC_LONG Name="WM/PeakBitrate" Value="3000" />
        <WMENC_STRING Name="Title" />
        <WMENC_STRING Name="Author" Value="MBC" />
        <WMENC_STRING Name="Copyright" Value="Motorola 2008" />
        <WMENC_STRING Name="Description" />
        <WMENC_STRING Name="WM/ParentalRating" />
    </Attributes>

    <RemoveAllMarkers />
    <RemoveAllScripts />
    <scripts >
        <script Type="URL"
            Command="slide1.jpg"
            Time="5000000" />
        <script Type="URL"
            Command="slide2.jpg"
            Time="464000000" />
        <script Type="URL"
            Command="slide3.jpg"
            Time="995000000" />
        <script Type="URL"
            Command="slide4.jpg"
            Time="2330000000" />
        <script Type="URL"
            Command="slide5.jpg"
            Time="3730000000" />
        <script Type="URL"
            Command="slide6.jpg"
            Time="6050000000" />
        <script Type="URL"
            Command="slide7.jpg"
            Time="7095000000" />
        <script Type="URL"
            Command="slide8.jpg"
            Time="8670000000" />
        <script Type="URL"
            Command="slide9.jpg"
            Time="10380000000" />
        <script Type="URL"
            Command="slide10.jpg"
            Time="11710000000" />
        <script Type="URL"
            Command="slide11.jpg"
            Time="13395000000" />
        <script Type="URL"
            Command="slide12.jpg"
            Time="14225000000" />
        <script Type="URL"
            Command="slide13.jpg"
            Time="16535000000" />
        <script Type="URL"
            Command="slide14.jpg"
            Time="17910000000" />
        <script Type="URL"
            Command="trailer.html??logo"
            Time="19620000000" />
    </Scripts>

</WMBasicEdit>

Test script -

#include <_XMLDomWrapper.au3>

_XMLFileOpen("test.txt")

_XMLDeleteNode("//Scripts/*")
_XMLCreateChildNode("//Scripts", "Script")
_XMLDeleteNode("//Scripts/*")
_XMLCreateChildNode("//Scripts", "Script")
_XMLDeleteNode("//Scripts/*")
_XMLCreateChildNode("//Scripts", "Script")
_XMLDeleteNode("//Scripts/*")
_XMLCreateChildNode("//Scripts", "Script")
_XMLDeleteNode("//Scripts/*")
_XMLCreateChildNode("//Scripts", "Script")
_XMLDeleteNode("//Scripts/*")
_XMLCreateChildNode("//Scripts", "Script")
_XMLDeleteNode("//Scripts/*")
_XMLCreateChildNode("//Scripts", "Script")
_XMLDeleteNode("//Scripts/*")
_XMLCreateChildNode("//Scripts", "Script")
_XMLDeleteNode("//Scripts/*")
_XMLCreateChildNode("//Scripts", "Script")
_XMLDeleteNode("//Scripts/*")
_XMLCreateChildNode("//Scripts", "Script")
_XMLDeleteNode("//Scripts/*")
_XMLCreateChildNode("//Scripts", "Script")
_XMLDeleteNode("//Scripts/*")
_XMLCreateChildNode("//Scripts", "Script")
_XMLDeleteNode("//Scripts/*")
Link to comment
Share on other sites

Well, I *kinda* fixed it by disabling AutoSave, then after manually saving the doc, re-opening it. The re-opening part is kinda lame, but it works if there's no other solution.

BTW, I'm on Vista 32-bit, and AutoIt beta 3.2.13.12

OH - bugfix!!

The _XMLSetAutoSave() function has the logic reversed. Oops...

Edited by wraithdu
Link to comment
Share on other sites

Reloading then manually saving the XML doc with _XMLSaveDoc() seems to remove the extra blank lines. I tried with all versions of the MSXML object, and they all have this problem. Try adding this to the end of my above test script -

$objDoc = 0
_XMLFileOpen("test.txt")
_XMLSaveDoc("test.txt")
Link to comment
Share on other sites

  • 2 weeks later...

I have an interesting problem.

XML

<Settings>
  <Syslog AP="0" Level="0" CC="0" IP="" CN="0"/> 
  </Settings>

CODE_1

Dim $name[1], $value[1]
_XMLFileOpen($filename)
$temp = _XMLGetAllAttrib("Settings/Syslog", $name, $value)

CODE_2

_XMLFileOpen($filename)
$temp = _XMLGetAttrib("Settings/Syslog", "AP")

CODE_1 could read attributes correctly, but CODE_2 cannot, it returns $temp = -1, and the error is "Attribute not found". What's the problem?

Thanks!

Link to comment
Share on other sites

How to insert a couple of nodes? For example

XML1

<Settings>
  <Syslog AP="0" Level="0" CC="0" IP="" CN="0"/>

  </Settings>

XML2

<SubSettings>
  <DebugLog JD="3" CCN="3" EC="3" MC="3" CC="3"/>
  <LeaveRegistry Enabled="0" /> 
  </SubSettings>

How to insert XML2 to the blank field of XML1?

Thanks!

Link to comment
Share on other sites

Sorry maybe I didn't explain it clearly.

The original XML is:

<Settings>
    <Syslog AP="0" Level="0" CC="0" IP="" CN="0"/>
  </Settings>

The XML to insert:

<SubSettings>
    <DebugLog JD="3" CCN="3" EC="3" MC="3" CC="3"/>
    <LeaveRegistry Enabled="0" />
  </SubSettings>

After insert, it should be:

<Settings>
    <Syslog AP="0" Level="0" CC="0" IP="" CN="0"/>
    <SubSettings>
      <DebugLog JD="3" CCN="3" EC="3" MC="3" CC="3"/>
      <LeaveRegistry Enabled="0" />
    </SubSettings>
  </Settings>

I don't want to create those nodes one by one. Is there any simple method to insert an existing XML?

Thanks!

Edited by scdxorange
Link to comment
Share on other sites

This is the only way it can be done reliably.

#include "_XMLDomWrapper.au3"

$sXMLFile = "test.xml"

$result = _XMLFileOpen($sXMLFile)
If $result = 0 Then Exit

If NOT _XMLNodeExists("//Settings/SubSettings") Then
    _XMLCreateChildNode("//Settings","SubSettings")
EndIf

Dim $aKeys[5] = ["JD", "CCN", "EC", "MC", "CC"], $aValues[5] = ["3", "3", "3", "3", "3"]

_XMLCreateChildWAttr("//Settings/SubSettings", "DebugLog",$aKeys,$aValues)

Dim $aKeys[1] = ["Enabled"], $aValues[1] = ["0"]

_XMLCreateChildWAttr("//Settings/SubSettings", "LeaveRegistry",$aKeys,$aValues)
Link to comment
Share on other sites

Can this wrapper be used to convert fields in one XML file into the format for a different XML file?

In other words, I want to convert an XML file into a new format for a different program to use.

Are there examples on the site forum that I missed?

This is called a transformation. This UDF can transform an XML file with a given XSL file. XSL is quite difficult so I will be of little help. Maybe if you could post a small sample of the original XML and the expected result I could take a look.

Link to comment
Share on other sites

Basically someone was asking about converting a movie xml file from a website into XBMC xml (which is called .nfo), like

<Titles>
  <Title>
    <ID>1</ID>
    <WebServiceID>bd4332a4-f545-4642-8ba2-68ba4b8371cf</WebServiceID>
    <CollectionNumber>1</CollectionNumber>
    <Type>DVD</Type>
    <Barcode>7321970139297</Barcode>
    <Country>Denmark</Country>
    <LocalTitle>The Brave One</LocalTitle>
    <OriginalTitle>The Brave One</OriginalTitle>
    <SortTitle>Brave One, The</SortTitle>
    <IMDB>tt0476964</IMDB>
    <Description><![CDATA[Hver dag fortæller New York'er radio-værten Erica Bain (Jodie Foster) levende om New York i sit show; om byens finurligheder, stemninger og alle lydene. Hun tager jævnligt ud i byen og optager lydklip, der senere bliver brugt i hendes programmer. Hun elsker virkelig byen, og det kan man mærke.
]]></Description>
    <ExtraFeatures NotPresent="True"><![CDATA[]]></ExtraFeatures>
    <ParentalRating Adult="False">
      <Value>6</Value>
      <Description>
      </Description>
    </ParentalRating>
    <Covers>
      <Front>C:\Documents and Settings\All Users\Application Data\My Movies\FileStorage\Covers\797f0ebb-a323-467d-b325-1f6c6feed116.jpg</Front>
      <Back>C:\Documents and Settings\All Users\Application Data\My Movies\FileStorage\Covers\63f5a41f-e833-4f3e-aec0-03966b50737b.jpg</Back>
    </Covers>
    <Genres>
      <Genre>Suspense/Thriller</Genre>
    </Genres>
    <Persons ActorsComplete="False">
      <Person Type="1">
        <Name>Naveen Andrews</Name>
        <Type>Actor</Type>
        <Role>David Kirmani</Role>
      </Person>
      <Person Type="1">
        <Name>Nicky Katt</Name>
        <Type>Actor</Type>
        <Role>Detective Vitale</Role>
      </Person>
    </Persons>
  </Title>
</Titles>

to XMBC like

<movie>
    <title></title>
    <originaltitle></originaltitle> // currently unused in YAMJ
    <rating></rating>              // 0 - 10 rating, can be decimal
    <year></year>
    <outline></outline>          // a short plot description
    <plot></plot>                  // a longer plot description
    <runtime></runtime>
    <thumb></thumb>              // url of poster image. use URL formatting, such as http:// for internet resources or file:// for local resources
    <fanart></fanart>              // url of fanart image. use URL formatting, such as http:// for internet resources or file:// for local resources
    <mpaa></mpaa>
    <id></id>                      // the IMDB id of the movie. includes the leading "tt"
    <genre></genre>              // multiple genre records may exist, including any custom ones
    <director></director>
    <actor>                      // multiple actor records may exist
        <name></name>
        <role></role>
    </actor>
</movie>

Of course there are more fields in both, some unused in XBMC, some not needed from original, but that's the beginning stages of conversion.

Link to comment
Share on other sites

Alright, here is a working transformation. Unfortunately there isn't enough information from the original XML to satisfy the expected xml.

#include "_XMLDomWrapper.au3"

$inFile = @ScriptDir & '\in.xml'
$outFile = @ScriptDir & '\out.xml'

$xsl = @ScriptDir & '\test.xsl'

$result = _XMLFileOpen($inFile)
If @ERROR <> 0 Then
    MsgBox(0,"","Error opening " & $inFile)
    Exit
EndIf

_XMLTransform($result, $xsl, $outFile)

test.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" encoding="utf-8"/>
 <xsl:template match="/">
 <movies>
 <xsl:for-each select="Titles/Title">
 <movie>
     <title><xsl:value-of select="LocalTitle"/></title>
     <originaltitle><xsl:value-of select="OriginalTitle"/></originaltitle> <!-- currently unused in YAMJ -->
     <rating></rating>             <!-- 0 - 10 rating, can be decimal -->
     <year></year>
     <outline></outline>             <!-- a short plot description -->
     <plot></plot>                 <!-- a longer plot description -->
     <runtime></runtime>
     <thumb></thumb>                 <!-- url of poster image. use URL formatting, such as http:// for internet resources or file:// for local resources -->
     <fanart></fanart>             <!-- url of fanart image. use URL formatting, such as http:// for internet resources or file:// for local resources -->
     <mpaa></mpaa>
     <id><xsl:value-of select="IMDB"/></id>                    <!-- the IMDB id of the movie. includes the leading "tt" -->
     <genre></genre>                 <!-- multiple genre records may exist, including any custom ones -->
     <director></director>
     <xsl:for-each select="Persons/Person">
     <actor>                         <!-- multiple actor records may exist -->
         <name><xsl:value-of select="Name"/></name>
         <role><xsl:value-of select="Role"/></role>
     </actor>
     </xsl:for-each>
 </movie>
 </xsl:for-each>
 </movies>
 </xsl:template>
 </xsl:stylesheet>

Result:

<?xml version="1.0" encoding="utf-8"?>
 <movies>
   <movie>
     <title>The Brave One</title>
     <originaltitle>The Brave One</originaltitle>
     <rating></rating>
     <year></year>
     <outline></outline>
     <plot></plot>
     <runtime></runtime>
     <thumb></thumb>
     <fanart></fanart>
     <mpaa></mpaa>
     <id>tt0476964</id>
     <genre></genre>
     <director></director>
     <actor>
       <name>Naveen Andrews</name>
       <role>David Kirmani</role>
     </actor>
     <actor>
       <name>Nicky Katt</name>
       <role>Detective Vitale</role>
     </actor>
   </movie>
 </movies>
Edited by weaponx
Link to comment
Share on other sites

I am trying to create a XML test log lib for my autoit test script by using XML Dom Wrapper. I would like to made function for my test log so that whenever I call for it a new entry will be appended onto the existing xml file. The file will be saved after every posting so that I won't have a broken xml if my test fails. I don't need to go back and modify the previous posting. I will use a XSL to format it for properly reading later.

I have some knowledge in XML but new to AutoIt & XML Dom Wrapper. I have tried to look thru the postings and use the example to create a simple xml structure. But then the child entries are based on index. I am not sure how to navigate it if I just wanted to append the new entry to the end of the structure. Is it possible for you to provide some help on this?

My XML test log format:

CODE

<?xml version="1.0" ?>

- <Event_Log>

- <TestLog ID="0001">

<Type>xxxx</Type>

<Message>xxxx</Message>

<Time>xxxx</Time>

<Picture>xxxx</Picture>

<Remarks>xxxx</Remarks>

</TestLog>

- <TestLog ID="0002">

<Type>xxxx</Type>

<Message>xxxx</Message>

<Time>xxxx</Time>

<Picture>xxxx</Picture>

<Remarks>xxxx</Remarks>

</TestLog> </Event_Log>
Link to comment
Share on other sites

This is a basic example. It relies on at least one entry to already be in the file. You can fix that by using XMLSelectNodes to see if there is at least one TestLog entry.

#include "_XMLDomWrapper.au3"

$sXMLFile = "logging.xml"
$root = "//Event_Log"

$result = _XMLFileOpen($sXMLFile)
If $result = 0 Then 
    MsgBox(0,"","File not found")
    Exit
EndIf

;Get last log id
$result = Number(_XMLGetAttrib($root & "/TestLog[last()]", "ID"))
If @ERROR Then
    ;ConsoleWrite("@ERROR: " & @ERROR & @CRLF)
    Exit
Else
    ;ConsoleWrite($result & @CRLF)
EndIf

_XMLCreateRootChild ("TestLog", "")
_XMLSetAttrib($root & "/TestLog[last()]", "ID", StringFormat("%04s",$result+1)) ;Increment, convert to string, pad to 4 characters
_XMLCreateChildNode ($root & "/TestLog[last()]", "Type", "xxxx")
_XMLCreateChildNode ($root & "/TestLog[last()]", "Message", "xxxx")
_XMLCreateChildNode ($root & "TestLog[last()]", "Time", "xxxx")
_XMLCreateChildNode ($root & "/TestLog[last()]", "Picture", "xxxx")
_XMLCreateChildNode ($root & "/TestLog[last()]", "Remarks", "xxxx")
Link to comment
Share on other sites

Thanks for the great help :)

Based on your example, I have created some working functions for test log posting. However, during the development, I noticed that sometime I need to create folders to contain multiple entries in order to organize them properly.

I have think of a function to create sub folder similar to CreatChildNode. The function can accept "Open" & "Close" control during my postings. So that I can call for it whenever I need to group certian number of entries. However when I started the development, I have faced some difficuties on how to handle the entries' running IDs, storage of current xpath, and handling of multiple level of folders.

Is it possible for you to provide me some insight on how to do it properly? I have attached my working code as a reference.

CODE
#Include "Date.au3"

#include "_XMLDomWrapper.au3"

;===============================================================================

;[Function Local Variable]

;_TestLog_Initiate()

Dim $s_xroot

;_TestLog_Message()

Dim $s_XMLFile

;===============================================================================

;===============================================================================

; Function Name: _TestLog_Initiate($s_Path)

; Category: Initiate, Test Log

; Description:: Create XML testlog template for logging.

; Parameter(s): [$s_XMLFile] - full path of test log file

; Requirement(s): #include <"_XMLDomWrapper.au3">

; Return Value(s): $s_xroot contains root xpath "//Test_Log".

; $s_XMLFile contains current working XML file.

; Author(s): Peter Yeung 13 Jan 2009

; Bugs: Overwrite existing test log file if exists

; Create root node "//Test_Log"

;===============================================================================

Func _TestLog_Initiate($s_Path)

;Create file (force overwrite existing file)

$result = _XMLCreateFile($s_Path, "Test_Log", 1)

Switch @error

Case 0

;"No error"

Case 1

MsgBox(0,"_TestLog_Initiate()","Failed to create file")

Case 2

MsgBox(0,"_TestLog_Initiate()","No object")

Case 3

MsgBox(0,"_TestLog_Initiate()","File creation failed MSXML error")

Case 4

MsgBox(0,"_TestLog_Initiate()","File exists")

EndSwitch

$s_xroot = "//Test_Log"

$s_XMLFile = $s_Path

EndFunc

;===============================================================================

; Function Name: _TestLog_Message($s_Path)

; Category: Message, Test Log

; Description:: Posting message into test log.

; Parameter(s): [$s_message] - string for [Message] tag.

; [$s_remarks] - string for [Remarks] tag.

; Requirement(s): #include <_XMLDomWrapper.au3>, #Include <Date.au3>

; _Testlog_Initiate()

; Dim $s_xroot, Dim $s_XMLFile

; Return Value(s): NA

; Author(s): Peter Yeung 13 Jan 2009

; Bugs: Create 1st node if no node is available

; Auto input DateTime in [Time] tag

; [DataPro] tag set to "Message"

;===============================================================================

Func _TestLog_Message($s_message, $s_remarks)

; Record posting time

$tCur = _Date_Time_GetLocalTime()

; Open XML file

$result = _XMLFileOpen($s_XMLFile)

If $result = 0 Then

MsgBox(0,"_TestLog_Message()","File not found")

Exit

EndIf

; Check if last node is available

$result = _XMLSelectNodes($s_xroot & "/Log[last()]")

If $result = -1 Then

; Create new child entry

_XMLCreateRootChild ("Log", "")

_XMLSetAttrib($s_xroot & "/Log[1]", "ID", StringFormat("%04s",1)) ;convert to string, pad to 4 characters (4 digits)

_XMLCreateChildNode ($s_xroot & "/Log[last()]", "Message", $s_message)

_XMLCreateChildNode ($s_xroot & "/Log[last()]", "Time", _Date_Time_SystemTimeToDateTimeStr($tCur))

_XMLCreateChildNode ($s_xroot & "/Log[last()]", "Picture", "")

_XMLCreateChildNode ($s_xroot & "/Log[last()]", "Remarks", $s_remarks)

_XMLCreateChildNode ($s_xroot & "/Log[last()]", "DataPro", "Message")

Else

; Get last entry id

$result = Number(_XMLGetAttrib($s_xroot & "/Log[last()]", "ID"))

; Append new child entry

_XMLCreateRootChild ("Log", "")

_XMLSetAttrib($s_xroot & "/Log[last()]", "ID", StringFormat("%04s",$result+1)) ;Increment, convert to string, pad to 4 characters (4 digits)

_XMLCreateChildNode ($s_xroot & "/Log[last()]", "Message", $s_message)

_XMLCreateChildNode ($s_xroot & "/Log[last()]", "Time", _Date_Time_SystemTimeToDateTimeStr($tCur))

_XMLCreateChildNode ($s_xroot & "/Log[last()]", "Picture", "")

_XMLCreateChildNode ($s_xroot & "/Log[last()]", "Remarks", $s_remarks)

_XMLCreateChildNode ($s_xroot & "/Log[last()]", "DataPro", "Message")

EndIf

EndFunc

;----------------------------------End of Code----------------------------------

;Code example:

$TempXML = @ScriptDir & "\example.xml"

_TestLog_Initiate($TempXML)

_TestLog_Message("Testing...", "Testing...")

Sleep (5000)

_TestLog_Message("Testing...2", "Testing...2")

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...