Пакетная вставка элемента из 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 из этот сайт.