Пакетная вставка элемента из XML с общим именем файла
Я пытаюсь вставить 800 уникальных элементов <REMARK>this is a remark</REMARK>
в существующий набор из 800 XML файлов. Я создал 800 документов только с элементом <REMARK>
, который я хочу добавить в каждый XML. Мысль, я мог бы вставить этот элемент в соответствующий XML-документ на основе общего имени файла. Например, у меня есть XML под названием WNYC-SCHK-2004-02-20-37540.xml в одной папке с только этой информацией в нем <REMARK>Think of Spanish classical music and the name Manuel de Falla naturally comes to mind.</REMARK>
И я хочу вставить элемент в файл также названный WNYC-SCHK-2004-02-20-37540.xml чуть ниже элемента <CHANGETIME>
ниже:
<?xml version="1.0" encoding="ISO-8859-1"?>
<ENTRIES>
<ENTRY>
<NUMBER>622</NUMBER>
<CLASS>Audio</CLASS>
<TITLE>WNYC-SCHK-2004-02-20-37540</TITLE>
<GENERATOR>DBM</GENERATOR>
<CREATOR>JPASSMOR</CREATOR>
<DATE>2015-01-06</DATE>
<DATUM>2015-01-06</DATUM>
<TIME>11:48:59</TIME>
<TIMESTAMP>2015-01-06 11:48:59</TIMESTAMP>
<LENGTH>00:58:53.920</LENGTH>
<DURATION>3533920</DURATION>
<SOFTDELETED>0</SOFTDELETED>
<NODELETE>0</NODELETE>
<READY>0</READY>
<PERFECT>0</PERFECT>
<FORARCHIVE>0</FORARCHIVE>
<ARCHIVING>0</ARCHIVING>
<ARCHIVED>0</ARCHIVED>
<GROWING>0</GROWING>
<NEW>0</NEW>
<INVALID>0</INVALID>
<LOWRESEXISTS>0</LOWRESEXISTS>
<KEYFRAMEEXISTS>0</KEYFRAMEEXISTS>
<VSAT>0</VSAT>
<LOOP>0</LOOP>
<INVISIBLE>0</INVISIBLE>
<SHAREDAUDIO>0</SHAREDAUDIO>
<TRANSMITTED>0</TRANSMITTED>
<ROYALTIES>0</ROYALTIES>
<WITHTEXTFILE>0</WITHTEXTFILE>
<INDEXED>0</INDEXED>
<PERSONALRADIO>0</PERSONALRADIO>
<REQUESTDEARCHIVE>0</REQUESTDEARCHIVE>
<REPLFLAGS>0</REPLFLAGS>
<STATE>Existing</STATE>
<AUTHOR>ARCHIVES</AUTHOR>
<EDITOR>JPASSMOR</EDITOR>
<CHANGEUSER>JPASSMOR</CHANGEUSER>
<CHANGEDATE>2015-01-26</CHANGEDATE>
<CHANGETIME>09:33:07</CHANGETIME>
<FILESIZE>628255824</FILESIZE>
<AUDIOFORMAT>Wave,BWF,RIFF</AUDIOFORMAT>
<AUDIOMODE>Stereo</AUDIOMODE>
<SAMPLERATE>44100</SAMPLERATE>
<BITRATE>0</BITRATE>
<TEXTLENGTH>00:00:00.000</TEXTLENGTH>
<TEXTDURATION>0</TEXTDURATION>
<BROADCASTINGS>0</BROADCASTINGS>
<MARKIN>00:00:00.000</MARKIN>
<MARKOUT>00:58:53.920</MARKOUT>
</ENTRY>
</ENTRIES>
чтобы он выглядел следующим образом:
<?xml version="1.0" encoding="ISO-8859-1"?>
<ENTRIES>
<ENTRY>
<NUMBER>622</NUMBER>
<CLASS>Audio</CLASS>
<TITLE>WNYC-SCHK-2004-02-20-37540</TITLE>
<GENERATOR>DBM</GENERATOR>
<CREATOR>JPASSMOR</CREATOR>
<DATE>2015-01-06</DATE>
<DATUM>2015-01-06</DATUM>
<TIME>11:48:59</TIME>
<TIMESTAMP>2015-01-06 11:48:59</TIMESTAMP>
<LENGTH>00:58:53.920</LENGTH>
<DURATION>3533920</DURATION>
<SOFTDELETED>0</SOFTDELETED>
<NODELETE>0</NODELETE>
<READY>0</READY>
<PERFECT>0</PERFECT>
<FORARCHIVE>0</FORARCHIVE>
<ARCHIVING>0</ARCHIVING>
<ARCHIVED>0</ARCHIVED>
<GROWING>0</GROWING>
<NEW>0</NEW>
<INVALID>0</INVALID>
<LOWRESEXISTS>0</LOWRESEXISTS>
<KEYFRAMEEXISTS>0</KEYFRAMEEXISTS>
<VSAT>0</VSAT>
<LOOP>0</LOOP>
<INVISIBLE>0</INVISIBLE>
<SHAREDAUDIO>0</SHAREDAUDIO>
<TRANSMITTED>0</TRANSMITTED>
<ROYALTIES>0</ROYALTIES>
<WITHTEXTFILE>0</WITHTEXTFILE>
<INDEXED>0</INDEXED>
<PERSONALRADIO>0</PERSONALRADIO>
<REQUESTDEARCHIVE>0</REQUESTDEARCHIVE>
<REPLFLAGS>0</REPLFLAGS>
<STATE>Existing</STATE>
<AUTHOR>ARCHIVES</AUTHOR>
<EDITOR>JPASSMOR</EDITOR>
<CHANGEUSER>JPASSMOR</CHANGEUSER>
<CHANGEDATE>2015-01-26</CHANGEDATE>
<CHANGETIME>09:33:07</CHANGETIME>
<REMARK>Think of Spanish classical music and the name Manuel de Falla naturally comes to mind.</REMARK>
<FILESIZE>628255824</FILESIZE>
<AUDIOFORMAT>Wave,BWF,RIFF</AUDIOFORMAT>
<AUDIOMODE>Stereo</AUDIOMODE>
<SAMPLERATE>44100</SAMPLERATE>
<BITRATE>0</BITRATE>
<TEXTLENGTH>00:00:00.000</TEXTLENGTH>
<TEXTDURATION>0</TEXTDURATION>
<BROADCASTINGS>0</BROADCASTINGS>
<MARKIN>00:00:00.000</MARKIN>
<MARKOUT>00:58:53.920</MARKOUT>
</ENTRY>
</ENTRIES>
Я подумал, что может быть способ использовать xsl для копирования комментария из одного документа xml в другой на основе общего имени файла в пакете. Или может быть более простой способ сделать это?
Ответы
Ответ 1
Эта проблема имеет интересный аспект, поэтому я использовал ее для тестирования другого метода обработки файлов.
@echo off
setlocal EnableDelayedExpansion
rem Process all .xml files in current directory
for %%a in (*.xml) do (
rem Locate the line numbers where "CHANGETIME" and "/ENTRIES" appears
set "insertLine="
for /F "delims=:" %%b in ('findstr /N "CHANGETIME /ENTRIES" "%%a"') do (
if not defined insertLine (
set "insertLine=%%b"
) else (
set "lastLine=%%b"
)
)
rem Block used to read-input-file/create-output-file
< "%%a" (
rem Read the first line from input file
set /P "line="
rem Copy lines up to the insertion point
for /L %%i in (1,1,!insertLine!) do set /P "line=!line!" & echo/
rem Insert the corresponding REMARK file
type "RemarksFolder\%%a"
rem Copy the rest of lines
set /A insertLine+=1
for /L %%i in (!insertLine!,1,!lastLine!) do set /P "line=!line!" & echo/
) > "output.tmp"
rem Block-end
rem Replace input file with created output file
move /Y "output.tmp" "%%a" > NUL
)
Эта программа должна работать быстрее, чем другие методы, которые сравниваются по строкам; однако недостатком является то, что ведущие пробелы удаляются со всех строк. Хотя дополнительный код может быть вставлен, чтобы исправить этот момент, выполнение этого замедлит процесс...
Ответ 2
Пакетная среда не очень сильно подходит для управления XML как XML. Вероятно, существует способ использования Windows Script Host (VBScript или JScript) для оценки XML DOM, но в этой ситуации, вероятно, проще просто использовать циклы for
и echo
s.
Прочтите замечания в следующем примере Script для полного объяснения того, как это работает.
@echo off
setlocal
set "remarkDir=remarks\"
set "xmlDir=xml\"
rem // for all files in xmlDir\*.xml
for %%I in ("%xmlDir%\*.xml") do (
rem // echo filename without line break...
set /P "=Processing %%~nxI... "<NUL
rem // Read corresponding remark file into variable
set /P "remark=" <"%remarkDir%\%%~nxI"
rem // for each line in xmlDir\file.xml
for /f "usebackq delims=" %%X in ("%%~fI") do (
rem // append the line to a new file
>>"%%~dpnI.new" echo/%%X
rem // check whether the line contains /CHANGETIME
set "line=%%X"
setlocal enabledelayedexpansion
if not "%%X"=="!line:/CHANGETIME=!" (
rem // Line contains /CHANGETIME. Append remark.
>>"%%~dpnI.new" echo/!remark!
)
endlocal
)
rem // End of xml file. Replace old with new.
move /y "%%~dpnI.new" "%%~fI" >NUL
echo Done.
)
note: StackOverflow не предназначен для бесплатной службы кодирования, но я сочувствую вам. Похоже, вы приложили много усилий, чтобы покрасить себя в этот уголок. Поэтому я надеюсь, что это поможет вам.
Ответ 3
Простите. В моем первом ответе я сказал, что хочу использовать эту проблему в качестве теста, потому что это интересный аспект. Некоторое время назад я написал вспомогательную программу FilePointer.exe, которая позволяет перемещать указатель файла перенаправленного файла через стандартный дескриптор. Эта программа может быть использована для решения этой проблемы очень простым способом (а также любой другой проблемой с подобной структурой), поскольку прежний метод копирования нескольких строк с помощью команды FOR может быть изменен путем перемещения прямого указателя файла к определенной позиции файла, или простой командой FINDSTR для копирования остальных строк. Вот он:
@echo off
setlocal EnableDelayedExpansion
rem Example of use of FilePointer.exe auxiliary program
rem Antonio Perez Ayala
rem Process all .xml files in current directory
for %%a in (*.xml) do (
rem Locate the insertion offset where "FILESIZE" line starts
for /F "delims=:" %%b in ('findstr /O "FILESIZE" "%%a"') do set "insertPoint=%%b"
rem Block used to edit the file via redirected Stdin and Stdout
< "%%a" (
rem Set Stdin file pointer at the insertion point
FilePointer 0 !insertPoint!
rem Copy the rest of lines to an auxiliary file
findstr "^" > auxiliary.tmp
rem "FIND and MORE works different than FINDSTR."
rem "FIND and MORE first resets the file position variable and then read the complete file to the EOF,"
rem "If you use FINDSTR it simply reads the next data from current position, ..."
rem http://www.dostips.com/forum/viewtopic.php?f=3&t=2128&p=9720#p9720
rem Set Stdout file pointer at the insertion point
FilePointer 1 !insertPoint!
rem Insert the corresponding REMARK file
type "RemarksFolder\%%a"
rem And add the rest of lines
type auxiliary.tmp
) >> "%%a"
rem Block-end
)
del auxiliary.tmp
Этот метод имеет несколько преимуществ перед первым. Он работает быстрее, а ведущие пробелы сохраняются. Первая часть файла хранится в том же файле, то есть нет необходимости копировать его во временный файл. В этой задаче необходимо скопировать строки из точки ввода в EOF во временном файле, чтобы освободить место для вставленного текста, но в другой проблеме, которая просто нуждается в замене текста другим размером того же размера, изменение происходит незамедлительно без дальнейшей обработки независимо от размера файла! Если новый текст будет короче исходного, необходимо будет "уплотнить" данные после точки замены, а затем обрезать оставшиеся данные, что может быть сделано с помощью Truncate.exe(еще одна из моих вспомогательных программ).
Вы можете загрузить вспомогательную программу FilePointer.exe из этот сайт.