xml batch-file xslt merge

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.