Jump to content

Copying an XML file & Editing it and copying back


coles
 Share

Recommended Posts

Hi All,

Need a help with Autoit task, I am trying to copy an XML file and edit that XML file and copy it back

The script i have attached if the script we use to copy files to client from server, so basically what it does is

Going through a Set of IP address and 

  • Map the drive
  • Copy the file
  • Write copy process was success
  • Goes on a loop through IP's to check all machines have updated files  
#include <File.au3>
#include <iNet.au3>
#include <_XMLDomWrapper.au3>

func latestUpdate($address, $name)
  Local $result
   Local $hFileIndexHTML
   DriveMapDel ( "G:" )
   ConsoleWrite('Trying: ' & $address & "/" & $name & @CRLF);
   $result = DriveMapAdd ( "G:", "\\" & $address & "\C$", 0, $name & "\adminname","adminpswd")
   ;Copying the file from Mapped drive to local 
   if $result = 1 Then
      FileCopy( "G:\Program Files\test.xml", "C:\sample\test.xml", 1);
      ConsoleWrite('Copying Updated File: ' & $address & @CRLF);
      $hFileIndexHTML = FileOpen("C:\sample\test.txt", 1)
      FileWrite($hFileIndexHTML, $address & @CRLF)
      FileClose($hFileIndexHTML)
   EndIf
   
EndFunc

func done($file, $address)
   For $i = 1 to _FileCountLines($file)
       $line = FileReadLine($file, $i)
       if ( $address = $line ) Then
         ConsoleWrite('Already done: ' & $file & " " & $address & @CRLF);
         return true
       EndIf
    Next
    return false
EndFunc


func getMachineName($ipaddress)
  return _TCPIpToName($ipaddress)
EndFunc

func process($address)

 local $machineName
 $machineName = getMachineName($address)


  if ($machineName = "") Then
     ConsoleWrite("No machine found at:" & $address & @CRLF)
  Else
     ConsoleWrite("Machine found at:" & $address & " - " & $machineName & @CRLF)

  if ( done( "C:\sample\test.txt", $address) = false ) then
   if ( $machineName <> "" ) then
     latestUpdate($address, $machineName)
   else
   endif
   endif

EndIf


EndFunc


TCPStartup()

while 1=1
   
   PROCESS("10.10.1.1")

sleep( 1000 * 60 * 10)

wend

The XML file i am trying to copy is unique and different in all machines (Machine name,ID's etc), But whole structure is the same (ie, the num of lines ) [That's the reason i can't copy a single file to all the machines].

I was thinking of using _FileWriteToLine  to replace 3 lines with new data 

eg:

_FileWriteToLine("c:\sample\test.xml", 71,  "<RIA>"http://goog.html"</RIA>", True) 

_FileWriteToLine("c:\sample\test.xml", 350,  "<col header="Status" width="7%" dataFld="status_code" style="" preprocesser="processES" template="" hidden="0"/>", True) 

_FileWriteToLine("c:\sample\test.xml", 650,  "<col header="Units" width="11%" dataFld="units" style="" preprocesser="" template="fU(units)" hidden="0"/>", True) 

These lines inside XML  

340<em>

341<gd

342-360 is similar as blah blah <col header="Status" width="7%" dataFld="status_code" style="" preprocesser="processES" template="" hidden="0"/>

same goes for 650th line also

 

I would like to get opinion of copying this file as this is a highly critical file needed to keep machines running

 

  1. Do you think using _file write to line is risky?.
  2. Do you think i have to copy the file from parent folder to another folder after replacing the lines and then copy from there back to client system.

This is all what i can think now, Any comments/suggestions will be much appreciated.

 

 

 

 

 

Edited by coles
Missed out few words
Link to comment
Share on other sites

If you check the number of lines of the target.xml are the same as the source.xml the _FileWriteToLine method should be fine, if they don't have the same number of lines just write to a network share that they aren't equal and you can check on these machines at a later stage.  One note you would have to enclose those _FileWriteToLine lines with single quote ' at the beginning and end, as the lines you posted would error because of the internal double quotes.  I would also backup the target.xml file before making changes, something like: FileCopy("<Path to Target.xml", @LocalAppDataDir & "\Backup\Target.xml", 8) that way you can restore the file if it fails.

Alternatively you could use XML Dom which I see you have included in your script and then just use _XMLSetAttrib to change the code. 

Link to comment
Share on other sites

Thank you @Subz for the quick reply.

Yes i have checked the number of lines of both target and source, both are same.

Thanks for that tip regarding Single quote as i was having trouble initially.

 Easiest code i can think of is

FileCopy( "G:\Program Files\test.xml", "C:\sample\test.xml", 1);
-FileWritetoline...
-FileWritetoline...
-FileWritetoline...
Sleep(2000)
FileCopy( "C:\sample\test.xml", "G:\Program Files\test.xml", 1);
      ConsoleWrite('Copying Updated File: ' & $address & @CRLF);
      $hFileIndexHTML = FileOpen("C:\sample\test.txt", 1)
      FileWrite($hFileIndexHTML, $address & @CRLF)
      FileClose($hFileIndexHTML)

This works perfectly fine and functioning as needed.

Only thing is now i think about the source file, it may not be same in all machines. As i might have edited may be 5-10% of them every now and then with no thoughts about such a need will arise in the future. :(

Is there a way where the text change's can be made to the xml file to those specific lines, irrespective of the line number. 

Any help will be appreciated 

Link to comment
Share on other sites

@FrancescoDiMuro Hi i am adding a sample of source file.

what i am expecting from my script is changes in

line 71 existing[<ReferenceInformationAction>"C:\Program Files\Internet Explorer\iexplore.exe" -k "c:\temp\temp.html"</ReferenceInformationAction>] to [<ReferenceInformationAction>"C:\Program Files\Internet Explorer\iexplore.exe" -k "http:\\10.1.1.1\temp.html"</ReferenceInformationAction>]  

Line 375 existing[<col header="Location" width="30%" dataFld="location" style="" preprocesser="" template="formatUnitLocation(location, unid)" hidden="1"/>]to[<col header="Location" width="30%" dataFld="location" style="" preprocesser="" template="formatUnitLocation(location, unid)" hidden="0"/>]

Line 376 existing [<col header="DGroup" width="10%" dataFld="dgroup" style="" preprocesser="" template="" hidden="0"/>] to [<col header="DGroup" width="10%" dataFld="dgroup" style="" preprocesser="" template="" hidden="1"/>]

at the moment with the above script [in orginal post & reply to subz] i am able to change by over writing the specific lines.

Looking for a dynamic approach to do the changes by not depending on the line numbers.

 

Sample.xml

Link to comment
Share on other sites

You could use something like:

#include <_XMLDomWrapper.au3>

Global $g_bSaveXml = False
Global $g_sSample = @ScriptDir & "\sample.xml"
Global $g_sRefNode = '//mobilePublicSafety/settings/customparam/ReferenceInformationAction'
Global $g_sLocNode = '//mobilePublicSafety/settings/monitors/unitMonitor/grid/col[@dataFld="location"]'
Global $g_sDGrNode = '//mobilePublicSafety/settings/monitors/unitMonitor/grid/col[@dataFld="dgroup"]'
_XMLFileOpen($g_sSample, "", -1, False)
    Switch @error
        Case 1
            MsgBox(16, "XML File Open Error", 'An error occurred while attempting to parse ' & @CRLF & $g_sSample)
            Exit
        Case 2
            MsgBox(16, "XML File Open Error", 'No object was found while attempting to parse ' & @CRLF & $g_sSample)
            Exit
    EndSwitch

Local $oRefNode = $objDoc.selectSingleNode($g_sRefNode)
If IsObj($oRefNode) Then
    Local $sRefNode = $oRefNode.Text
    If $sRefNode = '"C:\Program Files\Internet Explorer\iexplore.exe" -k "c:\temp\temp.html"' Then
        $oRefNode.Text = '"C:\Program Files\Internet Explorer\iexplore.exe" -k "http:\\10.1.1.1\temp.html"'
        $g_bSaveXml = True
    EndIf
EndIf

Local $oLocNode = $objDoc.selectSingleNode($g_sLocNode)
If IsObj($oLocNode) Then
    Local $sLocNode = $oLocNode.getAttribute("hidden")
    If $sLocNode = 1 Then
        $oLocNode.setAttribute("hidden", 0)
        $g_bSaveXml = True
    EndIf
EndIf

Local $oDGrNodeNode = $objDoc.selectSingleNode($g_sDGrNode)
If IsObj($oDGrNodeNode) Then
    Local $sDRgNode = $oDGrNodeNode.getAttribute("hidden")
    If $sDRgNode = 0 Then
        $oDGrNodeNode.setAttribute("hidden", 1)
        $g_bSaveXml = True
    EndIf
EndIf

If $g_bSaveXml Then $objDoc.Save("sample.xml")

 

Link to comment
Share on other sites

@Subz Thank you so much for the effort to write it down and test it for me.

I guess it was one of your sleepless bored nights :), but really beneficial for me.

Once again thanks for your help :)

 

After going through help file just out of curiosity wanted to know, why you choose the above method. Instead of going with _ReplaceStringInFile

 

Link to comment
Share on other sites

XPaths can be made contextual too.  Say you are attempting to replace a node value, but it's inside another node with some known attribute.  You would have to reinvent the wheel to determine which child node to update with just a string replace; where with an xpath, you can do something like this to get the proper node:

"//some/parent[@name='ThisIsTheParent']//child"

There could be a million parent nodes, with unique name attributes, and you would be able to grab the child in one swoop rather than create complicated regular expressions or loops.  Of course, there is a bit to the learning curve in creating well formed xpaths as well.

Edited by jdelaney
IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.
Link to comment
Share on other sites

Thank you @Subz, i didn't know that if a character was out of place _ReplaceStringInFile will fail.

Thanks @jdelaney yes i will try more examples with well formed xpaths, so that next time it will be easier.

 

I would mark this topic as fixed, as @Subz solution have been working awesome for me.

His way of getting the results were far better and dynamic than mine. 

 

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

×
×
  • Create New...