Elemento de inserción por lotes desde XML con nombre de archivo compartido
batch-file xslt (3)
Estoy tratando de insertar 800 elementos únicos <REMARK>this is a remark</REMARK>
en un conjunto existente de 800 archivos XML. Genere 800 documentos con solo el elemento <REMARK>
que quiero insertar en cada XML. Pensándolo bien, podría insertar este elemento en el documento XML correspondiente, basado en un nombre de archivo compartido. Por ejemplo, tengo un XML llamado WNYC-SCHK-2004-02-20-37540.xml en una carpeta con solo esta información en él <REMARK>Think of Spanish classical music and the name Manuel de Falla naturally comes to mind.</REMARK>
Y quiero insertar el elemento en un archivo también llamado WNYC-SCHK-2004-02-20-37540.xml justo debajo del elemento <CHANGETIME>
continuación:
<?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>
para que se vea así
<?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>
Pensé que podría haber una forma de usar xsl para copiar el comentario de un documento xml en el otro basado en un nombre de archivo compartido en un lote. ¿O podría haber una manera más fácil de hacerlo?
Este problema tiene un aspecto interesante, así que lo usé para probar un método diferente para procesar archivos.
@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
)
Este programa debe ejecutarse más rápido que otros métodos que se comparan línea por línea; sin embargo, tiene la desventaja de que los espacios iniciales se eliminan de todas las líneas. Aunque se puede insertar un código adicional para corregir este punto, hacerlo ralentizará el proceso ...
Disculpe. En mi primera respuesta, dije que quería utilizar este problema como prueba porque es un aspecto interesante. Hace algún tiempo escribí el programa auxiliar FilePointer.exe que permite mover el puntero del archivo de un archivo redirigido a través de su identificador estándar. Ese programa se puede usar para resolver este problema de una manera muy simple (y también cualquier otro problema con estructura similar) porque el método anterior de copiar varias líneas a través del comando FOR puede cambiarse mediante un movimiento directo de puntero de archivo a una posición de archivo determinada, o mediante un simple comando FINDSTR para copiar el resto de las líneas. Aquí está:
@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
Este método tiene varias ventajas sobre el anterior. Se ejecuta más rápido y los espacios principales se conservan. La primera parte del archivo se guarda en el mismo archivo , es decir, no necesita copiarlo en un archivo temporal. En este problema, es necesario copiar las líneas desde el punto de inserción al EOF en un archivo temporal para dejar espacio para el texto insertado, pero en otro problema que solo necesita reemplazar un texto por otro del mismo tamaño, ¡el cambio es inmediato sin procesamiento adicional sin importar el tamaño del archivo ! Si el nuevo texto fuera más corto que el original, sería necesario "compactar" los datos después del punto de reemplazo y luego truncar los datos restantes, eso se puede hacer con Truncate.exe (otro de mis programas auxiliares).
Puede descargar el programa auxiliar FilePointer.exe desde este sitio .
El entorno de proceso por lotes no es demasiado adecuado para manipular XML como XML. Probablemente exista una forma de usar Windows Script Host (VBScript o JScript) para evaluar el XML DOM, pero en esta situación, probablemente sea más fácil simplemente usar bucles y echo
.
Lea los comentarios en el siguiente script de ejemplo para obtener una explicación completa de cómo funciona.
@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.
)
nota: no pretende ser un servicio de codificación gratuito, pero le tengo simpatía. Parece que has puesto mucho esfuerzo en pintarte en esta esquina. Por lo tanto, espero que esto te ayude.