2009-12-22 253 views
4

我想知道是否有任何方法可以創建可以編輯XML文檔中的一行的批處理文件。該行將由前一行標識。這個想法如下:使用批處理文件編輯XML

If line == Csetting name="BaseDirectory" serializeAs="String"> 
    Next line = <value>User Input from begining of batch</value> 

是這樣的,甚至posible或我夢想在我的手段之外?感謝您的幫助和答案。

回答

6

您可能可能在一個批處理文件中一起工作以某種方式。但這會非常痛苦。首先,我知道沒有辦法可靠地將行讀入批處理文件中的變量,並將它們寫回到未改變的文件中。您可以轉義大多數有問題的字符(例如<,>,&,|,...),但仍然存在我無法解決的問題(如不匹配的引號),導致此類嘗試失敗可怕的。然後你仍然無法解析XML,但是你寧願使用單引號代替雙引號就可能很容易失敗的原始文本處理。或者在某個地方拋出額外的空間。或者你正在尋找的線被分成幾行。所有有效的XML,但是當沒有XML解析器在附近時,很難解析。

批處理文件語言並不適合這樣的任務。哎呀,它幾乎不適用於文本處理,但XML遠不止於此。使用VBScript和MSXML甚至PowerShell(如果適用),您可能會有更多的運氣(並且很有趣)。

VBScript可能是最理智的選擇,因爲您可以依賴它,幾乎可以在任何現代Windows機器上使用它。

您也可以使用XSLT並從命令行調用它。有足夠的XSLT處理器可以使用,並且生成XSLT文件實際上更簡單(但仍需要幾次轉義)。


注意,我可以是高級批處理文件用戶/程序員,但絕不具有權威性。也許這很容易,我太愚蠢了,看不到它。

+0

你是對的,這是不可能的,標準的Windows批處理命令。其可能性爲 – 2009-12-22 14:44:37

+0

。只是你會需要更多的時間和精力 – ghostdog74 2009-12-22 14:46:16

+0

好吧,引用/轉義問題目前沒有解決方案。我無法讀取諸如'a | b「<>&'這樣的行,並將其寫入文件中,未匹配的引號會導致通常的轉義機制失敗('set'foo =%foo:&= ^&%」' )。 – Joey 2009-12-22 14:50:51

1

肯定的是,本機,您可以使用批處理,但我建議你去學習和使用VBScript代替

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 

腳本保存爲edit.vbs和批處理

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

VBScript是如果你討厭使用其他工具如gawk/sed/Python/Perl或其他XML解析器/編寫器的想法,那麼除了跛子批處理之外,還有最好的方法。否則,你應該考慮使用這些更好的工具。

+0

(不寒而慄)我不downvoting,但每次我用MS基本它一直極端不情願和很多挫折 – 2009-12-22 14:45:12

+0

@Jason S - 你可以推薦一個更好的選擇,謝謝! – Adkins 2009-12-22 14:52:57

+1

如果你使用這樣的腳本,很好,但是使用XML對象來編輯XML,否則你的轉義問題依然存在,VBScript沒有什麼問題 - 如果你無法編譯東西 – 2010-11-17 23:00:37

1

XML不是基於行的,因此假定您可以逐行檢查文件中的某些內容,但要麼存在問題,要麼依賴於除XML之外的其他假設。 (如果你從某種類型的軟件中獲得文件,你怎麼知道它總是會以這種特定方式產生輸出線?)

說了這麼多,我想看看JSDB Javascript,其中內置了E4X。 E4X使操縱XML特別簡單,只要你可以將它全部讀入內存;它不是一個基於流的系統。雖然你可以在沒有E4X的情況下使用JSDB,並且使用流處理文件I/O:

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(); 
6

我其實已經有了這個答案。是的,這是痛苦的,但是我有一個類似的問題,我實際上並不知道VBScript(儘管我正在計劃學習它......),儘管我的問題發生在一位同事有一個客戶,他們有20,000個文件外部數據的轉換。所有的文件都是xml,它們都丟失了XML的第二行,這觸發了我們導入的文檔的重新導入。

我編寫了一個標準的批處理腳本,與另一個在StackOverflow上發現的批處理腳本允許我將文件分成兩部分,然後在它們之間插入我想要的代碼。現在我唯一的問題(可能是因爲懶惰或者我缺乏知識/耐心),我無法逃避這個問題。劇本一直在想我正試圖寫入一個無效的文件。我嘗試了各種方式來使用這個角色,但我希望它以一種可變的形式出現。不用說,我得到了它的工作(甚至)...

以下是我提供給我的同事的自述文件,以及每個文件的代碼。

的README.txt 問題: 文件的海量失蹤的代碼的字符串或片和需要被編輯

解決方案: 該工具需要分開的文件和注入一個字符串或代碼段然後將這些文件放回到另一個位置。

這個工具共有4個文件。

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

你需要做什麼:

  1. 編輯String_Insert_Launcher並把這個文件與你想編輯的文件的目錄。 注意這個文件必須與您要編輯的所有其他文件位於同一文件夾中。 你需要編輯變量,在這個文件中,以匹配文件系統 batchpath

  2. 編輯InsertString.bat並把這個文件中設置上述 的batchpath變量相同的目錄你需要在這個文件中編輯變量匹配你的文件系統 insertpath destpath top_last_line insert_last_line bot_last_line

  3. 編輯insert.txt並把這個文件中設置上述 的insertpath相同的目錄你需要將要插入的字符串插入文本文件中

  4. 檢查您的日誌並確保「Modified_Filelist.txt」(在%insertpath%中找到)中的文件數是與您開始使用的文件數量相同。

文件的明細:


* insert.txt *


在這個文件中,你會希望把你想插入文件中的文本你將目標。使用單獨文件的原因是,特殊字符(>,<,/,\,|,^,%等等)不會像批處理文件中的參數一樣處理。 該文件必須位於您將在InsertString.bat中設置的名爲'insertpath'的變量的相同位置,或者在批處理文件中作爲%insertpath%引用。


* InsertString.bat *


在這個文件中,你會發現,需要爲腳本的工作需要設置的變量。 變量包括:

  **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) 

此文件已在同一個位置,你會在String_Insert_Launcher.bat設置變量稱爲「batchpath」或批處理文件%batchpath%參考爲。


* String_Insert_Launcher.bat *


這是您將執行編輯的所有文件的腳本。從包含要編輯的文件的文件夾啓動此批處理腳本。該文件抓取所有文件名並在所有這些文件上運行InsertString.bat。 在這個文件裏你會發現一個可以爲腳本設置的可變參數。 包含變量: batchfilepath - 這是執行所有工作的實際批處理文件的位置。這個位置只是文件路徑,不包括任何文件名。

文件#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 

文件#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"> 

在你的情況下,你可能能夠使用2個文件...一個與<value>和一個與</value> (我知道這是馬虎,但它會工作...) 然後從我的批處理腳本InsertString.bat你會只需將下一個循環2x(每個文件一個)放在它們之間,你就可以把echo。%userInputFromBeginningofBatch%>> File。xml

就像我說過的,我知道這很麻煩,你可以在VBScript中更容易,但對於我們這些不知道它的人來說,這是一個可行的解決方案。

+1

+1,對於這種努力,即使這對批處理文件來說也是一團糟,並且還有一些有特殊字符的錯誤,例如驚歎號將從文件中刪除,每一行中會附加一個空格,空行將被刪除並且不計數。 – jeb 2011-10-24 13:27:16

+2

這是我在StackOverflow上的第一篇文章,但實際上我沒有任何問題可以正常工作。我確實注意到在行後面有一個額外的空間......我不得不回頭看看代碼,看看我是否可以避免這種情況,但是我沒有任何問題用這些空格加載xml。至於空行,你是對的。但最終的結果是正在編輯的文件。我從來沒有說過它會很漂亮!感謝+1和評論,不好意思看額外的空間。 – rud3y 2011-10-24 20:57:38

2

不好意思。我爲此帖子事先道歉。我知道這是一個非常古老的話題,但在閱讀了答案後,我無法抗拒發佈這個答案的誘惑。

通過批處理程序的XML文件的處理不只是簡單和直接,但在我的愚見,比VBScript中,PowerShell中,等所有的同類解決方案更容易在這裏:

@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 

以前的程序唯一的問題是它從XML文件中刪除空行,但通過添加更多的命令可以非常簡單地修復這些細節。上一頁程序可以修改爲不檢查整條生產線(如OP原先要求),但檢查三個部分,在過去的VBScript示例以同樣的方式:

(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