Редактировать XML с помощью командного файла - PullRequest
4 голосов
/ 22 декабря 2009

Мне интересно, есть ли способ создать командный файл, который может редактировать строки в XML-документе. Линия будет обозначена предыдущей строкой. идея будет выглядеть следующим образом:

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

что-то подобное даже возможно или я мечтаю не по средствам? Спасибо за помощь и ответы.

Ответы [ 5 ]

6 голосов
/ 24 октября 2011

У меня действительно есть ответ на это. Да, это больно, однако у меня была похожая проблема, и я на самом деле не знаю VBScript (хотя я планирую изучать его ...) в то время, когда моя проблема возникла с коллегой, имеющим клиента с 20 000 файлов, которые они порвали с преобразование внешних данных. Все файлы были в формате xml, и во всех них отсутствовала одна и та же вторая строка XML, которая вызвала повторную загрузку документа, который мы импортировали.

Я написал стандартный пакетный скрипт в тандеме с другим, который нашел в StackOverflow, который позволил мне разбить файлы на 2 части, а затем между ними вставить нужный мне код. Теперь моя единственная проблема (вероятно, из-за лени или отсутствия знаний / терпения) заключалась в том, что я не мог избежать проблемы <,>. Сценарий продолжал думать, что я пытался записать в файл, который был недействительным. Я испробовал все возможные способы использования этого символа, но хотел его в переменной форме. Само собой разумеется, у меня это работает (даже хорошо) ...

Ниже приведен файл readme, который я предоставил своему коллеге, вместе с кодом из каждого файла.

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 и поместите этот файл в тот же каталог, в котором вы установили путь вставки выше Вам нужно поместить строку (и), которую вы хотите вставить в ваш файл, внутри этого текстового документа

  4. Проверьте свои журналы и убедитесь, что количество файлов в «Modified_Filelist.txt» (находится в% insertpath%) совпадает с количеством файлов, с которого вы начали.

Разбивка файлов:


* insert.txt *


Внутри этого файла вы захотите поместить текст, который вы хотите вставить в файлы, на которые вы нацелены. Причина использования отдельного файла заключается в том, что специальные символы (>, <, /, \, |, ^,% и т. Д.) Не обрабатываются как аргументы в командном файле. Этот файл ДОЛЖЕН БЫТЬ в том же месте, что и переменная, которую вы установите в InsertString.bat с именем 'insertpath' или на которую есть ссылка в пакетном файле как% insertpath%. </p>


* 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 ON для всех этих файлов. Внутри этого файла вы найдете переменную, которую необходимо установить для работы скрипта. Переменная включена: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

ФАЙЛ № 3: Insert.txt

<Vocabulary="Conv">

В вашем случае вы можете использовать 2 файла ... один с <value> и один с </value> (Я знаю, что это небрежно, но это будет работать ...) Затем из моего пакетного скрипта InsertString.bat вы бы просто поместили цикл: next 2x (по одному для каждого из ваших файлов), а между ними вы бы поместили echo.

Как я уже сказал, я знаю, что это грязно, и вы можете сделать это намного проще в VBScript, но для тех из нас, кто этого не знает, это решение работает.

6 голосов
/ 22 декабря 2009

Вы, вероятно, могли бы взломать что-то вместе в командном файле, который работает как-то . Но это будет необычайно больно. Прежде всего, я не знаю способа надежного чтения строк в переменные в пакетном файле и записи их обратно в файл без изменений. Вы можете избежать большинства проблемных символов (таких как <, >, &, |, ...), но все еще есть проблемы, которые я не смог решить 1 (такие как непревзойденные кавычки), которые приведут к таким неудачным попыткам. Тогда вы все равно не сможете проанализировать XML, но вы предпочтете примитивную обработку текста, которая может легко потерпеть неудачу, как только возможно использование одинарных кавычек вместо двойных кавычек. Или где-то добавлено дополнительное пространство. Или искомая линия разбита на несколько строк. Весь действительный XML, но больно разбирать, когда рядом нет парсера XML.

Язык пакетных файлов не очень подходит для таких задач. Черт возьми, он едва работает для обработки текста, но XML далеко за его пределами. Вам может повезти (и получше) с использованием VBScript и MSXML или даже PowerShell (если применимо).

VBScript - это, пожалуй, самый вменяемый выбор, поскольку вы можете положиться на него, существующий практически на любой современной машине с Windows.

Вы также можете использовать XSLT и вызывать его из командной строки. Существует достаточно процессоров XSLT, которые можно использовать, и создание файла XSLT на самом деле намного проще (но все равно потребует нескольких экранирований).


1 Обратите внимание, что я могу быть опытным пользователем / программистом пакетных файлов, но ни в коем случае не авторитетным. Может быть, это легко возможно, и я просто слишком глуп, чтобы это увидеть.

2 голосов
/ 12 апреля 2013

Простите. Заранее извиняюсь за этот пост. Я знаю, что это очень старая тема, но после прочтения ответов здесь я не удержался от соблазна опубликовать этот ответ.

Обработка файла 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
1 голос
/ 22 декабря 2009

XML не основан на строках, поэтому предположение, что вы можете искать что-то в файле, проверяя его построчно, либо подвержено проблемам, либо основано на других предположениях, помимо XML. (если вы получаете файл из определенного типа программного обеспечения, откуда вы знаете, что он всегда будет генерировать выходные строки именно таким образом?)

Сказав это, я бы посмотрел на JSDB Javascript, который имеет E4X встроенный. E4X делает особенно простым манипулирование XML, если вы можете читать все это в память; это не потоковая система. Хотя вы можете использовать JSDB без E4X и обрабатывать файловый ввод / вывод с помощью потоков:

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();
1 голос
/ 22 декабря 2009

Конечно, изначально вы можете использовать пакетный режим, но я рекомендую вам изучить и использовать вместо него 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. В противном случае вам следует рассмотреть возможность использования этих лучших инструментов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...