DOS Batch:处理XML文件中的双引号

时间:2014-11-03 13:42:21

标签: xml batch-file quotation-marks

我编写了下面的代码来读取XML文件(file_1.xml和file_2.xml)并在标记之间提取字符串并将其写入TXT文件。问题是一些字符串包含双引号,然后程序将这些字符作为正确的指令(不是字符串的一部分)......

file_1.xml的内容:

<AAA>C086002-T1111</AAA>
<AAA>C086002-T1222 </AAA>
<AAA>C086002-TR333 "</AAA>
<AAA>C086002-T5444  </AAA>

file_2.xml的内容:

<AAA>C086002-T5555 </AAA>
<AAA>C086002-T1666</AAA>
<AAA>C086002-T1777 "</AAA>
<AAA>C086002-T1888          "</AAA>

我的代码:

@echo off

setlocal enabledelayedexpansion

for /f "delims=;" %%f in ('dir /b D:\depart\*.xml') do (

    for /f "usebackq delims=;" %%z in ("D:\depart\%%f") do (

        (for /f "delims=<AAA></AAA> tokens=2" %%a in ('echo "%%z" ^| Findstr /r "<AAA>"') do (

            set code=%%a
            set code=!code:""=!
            set code=!code: =!
            echo !code!

        )) >> result.txt
    )
)

我在result.txt中得到了这个:

C086002-T1111
C086002-T1222
C086002-T5444
C086002-T5555
C086002-T1666

事实上,8条线中有3条缺失。这些行包括双引号或包含双引号的后续行...

我如何处理这些字符并将它们视为字符串的一部分?

2 个答案:

答案 0 :(得分:2)

请注意 - 使用批处理解析XML是一项有风险的业务,因为XML通常会忽略空格。您编写的任何脚本都可能只需将XML重新格式化为另一个等效的有效表单即可解决。话虽如此......

我没有通过完全解释你观察到的行为来追踪问题,但不平衡的报价引起了这一行的问题:

(for /f "delims=<AAA></AAA> tokens=2" %%a in ('echo "%%z" ^| Findstr /r "<AAA>"') do (

您可以消除这个问题,并通过先前删除任何引号来使您的代码完成工作。

@echo off

setlocal enabledelayedexpansion
del result.txt
for /f "delims=;" %%f in ('dir /b D:\depart\*.xml') do (
  for /f "usebackq delims=;" %%z in ("D:\depart\%%f") do (
    set code=%%z
    set code=!code:"=!
    set code=!code: =!
    (for /f "delims=<AAA></AAA> tokens=2" %%a in ('echo "!code!" ^| Findstr /r "<AAA>"') do (
      echo %%a
    )) >> result.txt
  )
)

但是你有一个潜在的主要问题。 DELIMS不指定字符串 - 它指定字符列表。因此,DELIMS=<AAA></AAA>相当于DELIMS=<>/A。如果你的元素值中有A或/,那么你的代码就会失败。

有一种更好的方法:

首先,您可以使用FINDSTR一次性收集所有文件中的所有<AAA>----</AAA>行,而不进行任何循环:

findstr /r "<AAA>.*</AAA>" "D:\depart\*.xml"

每个匹配行将作为文件路径输出,后跟冒号,后跟匹配行,如:

D:\depart\file_1.xml:<AAA>C086002-T1111</AAA>

文件路径永远不能包含<>,因此您可以使用以下内容迭代结果,捕获相应的令牌:

for /f "delims=<> tokens=3" %%A in ( ...

最后,您可以在整个循环中放置括号,并重定向一次。我假设您希望每次运行都创建一个新文件,因此我使用>代替>>

@echo off
setlocal enabledelayedexpansion
>result.txt (
  for /f "delims=<> tokens=3" %%A in (
    'findstr /r "<AAA>.*</AAA>" "D:\depart\*.xml"''
  ) do (
    set code=%%A
    set code=!code:"=!
    set code=!code: =!
    echo(!code!
)

假设您只需要修剪前导或尾随空格/引号,那么解决方案就更简单了。它确实需要奇怪的语法来将引用指定为DELIM字符。请注意,最后一个^%%B之间有两个空格。第一个转义空间被视为DELIM字符。未转义的空格终止FOR / F选项字符串。

@echo off
>result.txt (
  for /f "delims=<> tokens=3" %%A in (
    'findstr /r "<AAA>.*</AAA>" "D:\depart\*.xml"'
  ) do for /f delims^=^"^  %%B in ("%%A") do echo(%%B
)

更新以回应评论

我假设您的数据值永远不会包含冒号。

如果要将源文件名附加到每行输出,则只需要更改第一个FOR / F以捕获第一个标记(源文件)以及第三个标记(数据值)。该文件将包含完整路径以及尾随冒号。第二个FOR / F使用~nx修饰符将文件附加到源数据字符串以仅获取名称和扩展名(无驱动器或路径),并且在DELIMS选项中添加冒号以便修剪尾部冒号关闭。

@echo off
>result.txt (
  for /f "delims=<> tokens=1,3" %%A in (
    'findstr /r "<AAA>.*</AAA>" "D:\depart\*.xml"'
  ) do for /f delims^=:^"^  %%C in ("%%B;%%~nxA") do echo %%C
)

答案 1 :(得分:0)

如果我保留@dbenham建议并完成它以回显文件名:

@echo off
>result.txt (
    for /f %%f in ("D:\depart\*.xml") do (
        for /f "delims=<> tokens=3" %%A in ('findstr /r "<AAA>.*</AAA>" "D:\depart\*.xml"') do (
             for /f delims^=^"^  %%B in ("%%A") do (
               echo %%B;%%f
             )
         )
     )
 )

感谢您对此代码的看法!