Edit XML with batch file

前端 未结 5 937
别那么骄傲
别那么骄傲 2021-01-06 06:41

I am wondering if there is any way to create a batch file that can edit a line in an XML document. The line would be identified by the preceding line. the idea would be as

相关标签:
5条回答
  • 2021-01-06 07:06

    Excuse me. I apologize in advance for this post. I know this is a very old topic, but after read the answers here I couldn't resist the temptation to post this answer.

    The processing of a XML file via a Batch program is not just straightforward and direct, but in my humble opinion, easier than any equivalent solution in VBScript, PowerShell, etc. Here it is:

    @echo off
    setlocal EnableDelayedExpansion
    set "greater=>"
    set targetLine=Csetting name="BaseDirectory" serializeAs="String"!greater!
    echo Enter the new line to insert below target lines:
    set /P nextLine=
    setlocal DisableDelayedExpansion
    
    (for /F "delims=" %%a in (document.xml) do (
       set "line=%%a"
       setlocal EnableDelayedExpansion
       echo !line!
       if "!line!" equ "!targetLine!" echo !nextLine!
       endlocal
    )) > newDocument.xml
    

    The only problem with previous program is that it delete empty lines from the XML file, but this detail may be fixed in a very easy way by adding a couple commands more. Previous program may be modified to not check the complete line (as the OP originally requested), but check three parts in the same way of the last VBScript example:

    (for /F "delims=" %%a in (document.xml) do (
       set "line=%%a"
       setlocal EnableDelayedExpansion
       echo !line!
       set lineMatch=1
       if "!line:Csetting name=!" equ "!line!" set lineMatch=
       if "!line:BaseDirectoy=!" equ "!line!" set lineMatch=
       if "!line:serializeAs=!" equ "!line!" set lineMatch=
       if defined lineMatch echo !nextLine!
       endlocal
    )) > newDocument.xml
    
    0 讨论(0)
  • 2021-01-06 07:08

    I actually have an answer for this. Yes it is painful, however I had a similar problem and I don't actually know VBScript (though I am planning on learning it...) for the time though my problem occurred with a coworker having a customer with 20,000 files they flubbed from a conversion of outside data. All files were xml and they all were missing the same 2nd line of the XML which triggered a refile of the document we were importing.

    I wrote a standard batch script in tandem with another I found on StackOverflow which allowed me to split the files into 2 parts and then in between them insert the code I wanted. Now my only problem (probably due to laziness or my lack of knowledge/patience) was that I couldn't escape the < , > problem. The script kept thinking that I was trying to write to a file, which was invalid. I tried all sorts of ways to use that character, but I wanted it in a variable form. Needless to say, I got it working (well even)...

    Below is the readme I provided to my coworker, along with the code from each file.

    README.txt Problem: Massive amount of files were missing a string or piece of code and need to be edited

    Solution: This tools takes apart files and injects a string or piece of code and then put the files back together in another location.

    There are a total of 4 files that come with this tool.

        **1 - _README.txt       - This file describes how to use the script
        **2 - insert.txt            - This file contains the text that will be inserted into the file you need edited.
        **3 - InsertString.bat      - This file contains the actual script that loops to restructure the file. Here you will find all the variables that need to be set to make this work.
        **4 - String_Insert_Launcher.bat    - This file is what you will launch to run the InsertString.bat file.
    

    What you need to do:

    1. Edit String_Insert_Launcher and place this file in the directory with the files you want to edit. NOTE It is imperative that this file be in the same folder as ALL of the rest of your files you want edited. You need to edit the variables in this file to match you filesystem batchpath

    2. Edit InsertString.bat and place this file in the same directory you set the batchpath variable above You need to edit the variables in this file to match your filesystem insertpath destpath top_last_line insert_last_line bot_last_line

    3. Edit the insert.txt and place this file in the same directory you set the insertpath above You need to put the string(s) you want to be inserted into your file inside this text document

    4. Check your logs and make sure that the number of files in the " Modified_Filelist.txt " (found in the %insertpath%) is the same as the number of file you started with.

    Breakdown of files:


    * insert.txt *


    Inside this file you will want to put the text that you want inserted into the files you will target. The reason for using a separate file is so that special characters (>,<,/,\,|,^,%,etc...) aren't treated like arguments within the batch file. This file HAS TO BE in the same location as the variable you will set in InsertString.bat called ' insertpath ' or referenced in the batch file as %insertpath%.


    * InsertString.bat *


    Inside this file you will find the variables that need to be set for the script to work. Variables included:

                **1. filelist - This sets the counter for counting how many files were edited *this should not be edited*
            **2. insertpath - This sets the path of insert.txt file containing the string you want to insert into the files that will be edited. If this location does not exist it will create it.
            **3. destpath - This sets the path for the location of the files after they're edited. If this location does not exist it will create it.
            **4. top_last_line - This sets the LAST GOOD LINE of the file that will be edited before the insert.txt is added. In essence this will split the file into 2 parts and add the contents of " insert.txt " into the middle of those 2 parts.
            **5. insert_last_line - This sets the number of lines to add to the file from insert.txt (i.e. if insert_last_line=2 then the top two lines will be added after top_last_line)
            **6. bot_last_line - This sets the last line of the original file (i.e. if there are 25 lines in the original file bot_last_line should be 25 - always over esitimate this, because if this number is less than the original not all lines will be rewritten to the new file)
    

    This file HAS TO BE in the same location as the variable you will set in String_Insert_Launcher.bat called ' batchpath ' or referenced in the batch file as %batchpath%.


    * String_Insert_Launcher.bat *


    This is the script you will execute to edit all the files. Launch this batch script FROM the folder with the files in it you want to edit. This file grabs all of the file names and runs the InsertString.bat ON all of these files. Inside this file you will find a varaible that nees to be set for the script to work. Variable included: batchfilepath - This is the location of the actual batch file that does all of the work. This location is JUST the filepath, not including any filenames.

    FILE #1: String_Insert_Launcher.bat

    @ECHO off
    TITLE Insert String to XML Script Launch File
    COLOR 02
    
    set batchfilepath=C:\JHA\Synergy\insertpath
    REM This is the location of the actual batch file that does all of the work. This location is JUST the filepath, not including any filenames.
    IF NOT exist  %batchfilepath% md %batchfilepath% 
    IF NOT exist %batchfilepath%\InsertString.bat goto pause
    
    :run
    for /f "delims=" %%f in ('dir /b /a-d-h-s') do "%batchfilepath%\InsertString.bat" %%f
    REM This command string gets the names of all of the files in the directory it's in and then runs the InsertString.bat file against every file individually.
    
    :pause
    cls
    echo.The file InsertString.bat is not in the correct directory.
    echo.Please put this file in the location listed below:
    echo.
    echo.-------------------------
    echo.%batchfilepath%
    echo.-------------------------
    echo.
    echo.When this file has been added press any key to continue running the script.
    pause
    goto run
    
    REM Insert String to XML Script
    REM Created by Trevor Giannetti
    REM An unpublished work
    

    FILE #2: Insert_String.bat

    @ECHO off
    TITLE Insert String to XML Script
    COLOR 02
    SETLOCAL enabledelayedexpansion
    
    REM From Command Line:              for /f "delims=" %f in ('dir /b /a-d-h-s') do InsertString.bat %f
    
    REM ---------------------------
    REM   *** EDIT VARIABLES BELOW ***
    REM ---------------------------
    
    set insertpath=C:\JHA\Synergy\insertpath
    REM This sets the path of insert.txt file containing the string you want to insert into the files that will be edited. If this location does not exist it will create it.
    set destpath=C:\JHA\Synergy\destination
    REM This sets the path for the location of the files after they're edited. If this location does not exist it will create it.
    set top_last_line=1
    REM This sets the LAST GOOD LINE of the file to be edited before the insert.txt is added. In essence this will split the file into 2 parts and add the contents of " insert.txt " into the middle of those 2 parts.
    set insert_last_line=1
    REM This sets the number of lines to add to the file from insert.txt (i.e. if insert_last_line=2 then the top two lines will be added after top_last_line)
    set bot_last_line=25
    REM This sets the last line of the original file (i.e. if there are 25 lines in the original file bot_last_line should be 25 - always over esitimate this, because if this number is less than the original not all lines will be rewritten to the new file)
    
    REM ---------------------------
    REM  *** DO NOT EDIT BELOW ***
    REM ---------------------------
    
    set filelist=0
    REM This sets the counter for counting how many files were edited
    IF '%1'=='' goto usage
    
    IF NOT exist %insertpath% md %insertpath%
    IF NOT exist %destpath% md %destpath%
    
    :top_of_file
    IF EXIST %destpath%\%1 set done=T
    IF EXIST %destpath%\%1 goto exit
    IF '%1'=='InsertString.bat' goto exit
    IF '%1'=='insert.txt' goto exit
    IF '%1'=='Modified_Filelist.txt' goto exit
    IF '%1'=='String_Insert_Launcher.bat'  goto exit
    set /a FirstLineNumber = 1
    REM This is the first line in the file that you want edited
    set /a LastLineNumber = %top_last_line%
    REM This is the last line in the file that you want edited
    
    SET /a counter=1
    
    for /f "usebackq delims=" %%a in (%1) do (
        if !counter! GTR !LastLineNumber! goto next
        if !counter! GEQ !FirstLineNumber! echo %%a >>  %destpath%\%1
        set /a counter+=1
    )
    
    goto next
    
    :next
    REM echo TEXT TO BE INSERTED >> %destpath%\%1
    REM goto bottom_of_file
    REM The above can be substituted for the rest of :next if you don't have special characters in the text you need inserted
    
    set /a FirstLineNumber = 1
    REM This is the first line in the file with the text you need inserted in the file you want edited
    set /a LastLineNumber = %insert_last_line%
    REM This is the last line in the file with the text you need inserted in the file you want edited
    
    SET /a counter=1
    for /f "usebackq delims=" %%a in (%insertpath%\insert.txt) do (
        if !counter! GTR !LastLineNumber! goto next
        if !counter! GEQ !FirstLineNumber! echo %%a >>  %destpath%\%1
        set /a counter+=1
    )
    REM The %insertpath%\insert.txt is the name of the file with the text you want inserted into the file you want edited
    
    goto bottom_of_file
    
    :bottom_of_file
    set /a FirstLineNumber = 1+%top_last_line%
    REM This is the first line in the second part of the file with the text you need inserted in the file you want edited
    set /a LastLineNumber = %bot_last_line%
    REM This is the last line in the second part of the file with the text you need inserted in the file you want edited
    REM The above is the split, after the top_of_file. The rest of the contents of the original file will be added after the text you want inserted is appended to the file
    
    SET /a counter=1
    
    for /f "usebackq delims=" %%a in (%1) do (
        if !counter! GTR !LastLineNumber! goto exit
        if !counter! GEQ !FirstLineNumber! echo %%a >>  %destpath%\%1
        set /a counter+=1
    )
    
    goto logging
    
    :logging
    IF NOT EXIST %insertpath%\Modified_Filelist.txt echo Modified File List: > %insertpath%\Modified_Filelist.txt
    for /f "tokens=1 delims=[]" %%a in ('find /v /c "" ^< %insertpath%\Modified_Filelist.txt') do (
    echo %%a - %1 >> %insertpath%\Modified_Filelist.txt
    )
    
    goto exit
    
    :usage
    cls
    echo Usage: InsertString.bat FILENAME 
    echo You are missing the file name in your string
    
    :exit
    IF '%done%'=='T' echo %1 Already exists in folder!
    IF '%done%'=='T' echo Not modifying %1
    IF '%done%'=='T' echo Moving on to next file...
    IF EXIST %destpath%\InsertString.bat del %destpath%\InsertString.bat
    IF EXIST %destpath%\insert.txt del %destpath%\insert.txt
    
    REM Insert String to XML Script
    REM Created by Trevor Giannetti
    REM An unpublished work
    

    FILE #3: Insert.txt

    <Vocabulary="Conv">
    

    In your case you might be able to use 2 files...one with <value> and one with </value> (I know this is sloppy, but it will work...) Then from my batch script InsertString.bat you would just put the :next loop 2x (one for each of your files) and in between them you would put echo.%userInputFromBeginningofBatch% >> File.xml

    Like I said, I know this is messy and you can doe it a lot easier in VBScript, but for those of us that don't know it this is a solution that does work.

    0 讨论(0)
  • 2021-01-06 07:16

    You probably could hack something together in a batch file that works somehow. But it will be extraordinarily painful. First of all, I know of no way of reliably reading lines into variables in a batch file and writing them back to a file unaltered. You can escape most of the problematic characters (such as <, >, &, |, ...) but there still are problems I couldn't solve1 (such as unmatched quotation marks) that will cause such attempts to fail horribly. Then you still wouldn't be able to parse XML but you'd rather to primitive text processing which may easily fail as soon as maybe single quotes are used instead of double quotes. Or an extra space is thrown in somewhere. Or the line you're looking for is split into several lines. All valid XML but painful to parse when no XML parser is around.

    The batch file language isn't really suited for such tasks. Heck, it barely works for text processing but XML is way beyond. You may have more luck (and fun) with using VBScript and MSXML or even PowerShell (if applicable).

    VBScript is probably the most sane choice here as you can rely on it existing on virtually any modern Windows machine.

    You could also use XSLT and call that from the command-line. There are enough XSLT processors out there that can be used and generating an XSLT file is actually much simpler (but will still require several escapings).


    1 Note that I may be an advanced batch file user/programmer but by no means authoritative. Maybe it's easily possible and I'm just too stupid to see it.

    0 讨论(0)
  • 2021-01-06 07:19

    XML isn't line-based, so an assumption that you can look for something in the file by checking it on a line-by-line basis, is either prone to problems, or relies on other assumptions besides XML. (if you are getting your file from a certain type of software, how do you know it is always going to produce output lines in that particular way?)

    Having said that, I'd take a look at JSDB Javascript, which has E4X built-in. E4X makes it particularly simple to manipulate XML, as long as you can read it all into memory; it's not a stream-based system. Though you could use JSDB without E4X and handle file I/O using streams:

    var Sin = new Stream('file://c:/tmp/testin.xml');
    var Sout = new Stream('file://c:/tmp/testout.xml','w');
    while (!Sin.eof)
    {
       var Lin = Sin.readLine();
       var Lout = some_magic_function(Lin); // do your processing here
       Sout.writeLine(Lout);
    }
    Sin.close(); Sout.close();
    
    0 讨论(0)
  • 2021-01-06 07:23

    sure, natively, you can use batch, but i recommend you to learn and use vbscript instead

    Set objFS=CreateObject("Scripting.FileSystemObject")
    strFile = WScript.Arguments.Item(0)
    strUserValue= WScript.Arguments.Item(1)
    Set objFile = objFS.OpenTextFile(strFile)
    Do Until objFile.AtEndOfStream
        strLine = objFile.ReadLine
        If  InStr(strLine,"Csetting name") >0 And _
            InStr(strLine,"BaseDirectory")> 0 And _
            InStr(strLine,"serializeAs=") > 0 Then      
            strLine=strLine & vbCrLf & "<value>" & strUserValue & "</value>"        
        End If 
        WScript.Echo strLine
    Loop
    

    save the script as edit.vbs and in your batch

    c:\test> cscript //nologo edit.vbs file "user value"
    

    vbscript is the best you got besides cripple batch, if you hate the idea of using other tools like gawk/sed/Python/Perl or other xml parsers/writers. Otherwise, you should consider using these better tools.

    0 讨论(0)
提交回复
热议问题