使用共享文件名从 XML 批量插入元素

Batch Insert Element from XML with Shared Filename

我正在尝试将 800 个独特的 <REMARK>this is a remark</REMARK> 元素插入现有的 800 个 XML 文件集中。我生成了 800 个文档,每个 XML 中只有我想要插入的 <REMARK> 元素。我的想法是,我可以根据共享文件名将此元素插入到相应的 XML 文档中。例如,我在一个文件夹中有一个名为 WNYC-SCHK-2004-02-20-37540.xml 的 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 文档批量复制到另一个基于共享文件名的文档中。或者有更简单的方法吗?

批处理环境并不是非常适合将 XML 操作为 XML。可能有一种使用 Windows 脚本宿主(VBScript 或 JScript)来计算 XML DOM 的方法,但在这种情况下,使用 for 循环和 echos.

阅读以下示例脚本中的备注,了解其工作原理的完整说明。

@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.
)

注意:Whosebug 并非旨在成为免费编码服务,但我对您表示同情。听起来你已经付出了很多努力来把自己描绘成这个角落。因此,我希望这对你有所帮助。

这个问题有一个有趣的方面,所以我用它来测试处理文件的不同方法。

@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

)

这个程序应该 运行 比其他逐行比较的方法更快;但是,它的缺点是所有行的前导空格都被删除了。虽然可能会插入额外的代码来解决这个问题,但这样做会减慢进程...

对不起。在我的第一个回答中,我说我想用这个问题作为测试,因为它很有趣。前段时间我写了 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 的行,以便为插入的文本腾出空间,但在另一个问题中,只需要将一个文本替换为另一个相同大小的文本,更改是立即进行的,无需进一步处理无论文件大小!如果新文本比原始文本短,则需要 "compact" 替换点之后的数据,然后 t运行 对剩余数据进行分类,这可以通过 Truncate.exe 完成(我的另一个辅助程序)。

您可以从 this site 下载 FilePointer.exe 辅助程序。