【问题标题】:Batch Insert Element from XML with Shared Filename使用共享文件名从 XML 批量插入元素
【发布时间】:2015-01-28 18:08:43
【问题描述】:

我正在尝试将 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 doc 复制到另一个。或者有没有更简单的方法?

【问题讨论】:

    标签: xml batch-file xslt merge


    【解决方案1】:

    批处理环境不太适合将 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.
    )
    

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

    【讨论】:

    • 我喜欢你的“虚荣”版本。 :)其实我觉得rem :: ...是Batch中最丑的形式之一……
    • 我知道,对吧?我希望 Stack Overflow 的 google-code-prettify 实现包括 DOS / Windows Batch 的语法高亮。也许有一天我会写它并将它作为一个问题提交给美化项目,然后它最终会在这里涓涓细流。
    【解决方案2】:

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

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

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

    【讨论】:

    • 您正在谈论丢失前导空格,但是通过将set /P "line=!line!" &amp; echo/ 替换为set /P "line=" &amp; echo(!line! 两次(删除第一个set /P "line=")是否可以避免这个问题?并且文件RemarksFolder\%%a的最后一行必须以换行符终止,否则文件%%a的下一行将附加到它...
    • ...为文件RemarksFolder\%%a 强制使用尾随换行符,您可以使用&lt; "RemarksFolder\%%a" find /V ""...
    【解决方案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(我的另一个辅助程序)来完成。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-10
      • 1970-01-01
      相关资源
      最近更新 更多