获取未格式化的XML文件中的特定标记与批处理文件之间的所有字符串

时间:2015-03-26 12:02:35

标签: xml string parsing batch-file

我正在尝试在XML文件中获取2个标签之间的字符串,以适应我在here中找到的解决方案。

这是我的批处理文件:

@echo off
setlocal EnableDelayedExpansion

(for /F "delims=" %%a in ('findstr /I /L "<Name>" contacts.xml') do (
   set "line=%%a
   set "line=!line:*<Name>=!"
   for /F "delims=<" %%b in ("!line!") do echo %%b
)) > list.txt

现在格式化XML时,我得到了所有的名字

<List>
   <Contacts>
      <Row>
         <Name>Carlos</Name>
         <Path>\Some\path\1</Path>
         <Hidden>False</Hidden>
      </Row>
      <Row>
         <Name>Fernando</Name>
         <Path>\Some\path\2</Path>
         <Hidden>False</Hidden>
      </Row>
      <Row>
         <Name>Luis</Name>
         <Path>\Some\path\3</Path>
         <Hidden>False</Hidden>
      </Row>
      <Row>
         <Name>Daniel</Name>
         <Path>\Some\path\4</Path>
         <Hidden>False</Hidden>
      </Row>
   </Contacts>
</List>
  

卡洛斯

     

费尔南多

     

路易斯

     

丹尼尔

但是当XML(这就是它的生成方式)在一行中我只得到第一个名字

<List><Contacts><Row><Name>Carlos</Name><Path>\Some\path\1</Path><Hidden>False</Hidden></Row><Row><Name>Fernando</Name><Path>\Some\path\1</Path><Hidden>False</Hidden></Row><Row><Name>Luis</Name><Path>\Some\path\1</Path><Hidden>False</Hidden></Row><Row><Name>Daniel</Name><Path>\Some\path\1</Path><Hidden>False</Hidden></Row></Contacts></List>
  

卡洛斯

我应该对批处理文件进行哪些更改,以便正确解析未格式化的XML文件?

3 个答案:

答案 0 :(得分:4)

正如Adriano在他的评论中暗示的那样,通过像正则表达式这样强大的工具解析XML是不受欢迎的。使用批处理解析XML要差得多。

除非您使用涉及FC命令的特殊技术,否则纯本地批处理无法使用超过8191字节的文本行 - 相信我,您不想去那里。没有理由期望XML文件小于8191字节,因此简短的答案基本上是 - 您无法使用本机批处理命令解析作为一个连续行存在的无格式XML。

我写了script based regular expression utility for batch called JREPL.BAT。它是一个混合的JScript /批处理脚本,可以在XP以后的任何Windows机器上本机运行。我建议将JREPL.BAT放在一个文件夹中(我使用c:\​​ utils),然后在PATH变量中包含该文件夹。

假设您从未拥有嵌套的<Name>元素,可以使用以下JREPL.BAT命令在大多数简单方案下解析您的名称。但是就像任何正则表达式“解决方案”一样,这段代码并不适用于所有情况。

jrepl "<Name>([\s\S]*?)</Name>" "$1" /m /jmatch /f "contacts.xml" /o "list.txt"

由于JREPL是一个批处理脚本,因此如果要在另一个批处理脚本中使用该命令,则必须使用CALL JREPL。

答案 1 :(得分:3)

在我回答之前,我应该指出,您的单行XML缺少</Row>关闭标记,而所有<Name>元素都包含Carlos。因此,在测试我的答案时,我使用了以下XML:

<List><Contacts><Row><Name>Carlos</Name><Path>\Some\path\1</Path><Hidden>False</Hidden></Row><Row><Name>Fernando</Name><Path>\Some\path\1</Path><Hidden>False</Hidden></Row><Row><Name>Luis</Name><Path>\Some\path\1</Path><Hidden>False</Hidden></Row><Row><Name>Daniel</Name><Path>\Some\path\1</Path><Hidden>False</Hidden></Row></Contacts></List>

每当您从XML或HTML操作或提取数据时,我认为通常最好将其解析为XML或HTML,而不是试图从中删除一些文本。 无论您的XML是否被美化或缩小,如果您将XML解析为XML,您的代码仍然可以正常工作。对于正则表达式或令牌搜索,也不能这样说。

纯批处理并不能很好地处理XML。但Windows Scripting Host可以。您最好的选择是使用JScript或VBscript,或者可能使用PowerShell。我的解决方案是批处理+ JScript混合脚本,使用Microsoft.XMLDOM COM对象和XPath查询来选择所有<Name>节点的文本子节点 - 基本上是selectNodes('//Name/text()')

使用.bat扩展名和盐来保存。

@if (@CodeSection == @Batch) @then

@echo off
setlocal

set "xmlfile=test.xml"

for /f "delims=" %%I in ('cscript /nologo /e:JScript "%~f0" "%xmlfile%"') do (
    echo Name: %%~I
)

rem // end main runtime
goto :EOF

@end
// end batch / begin JScript chimera

var DOM = WSH.CreateObject('Microsoft.XMLDOM');

with (DOM) {
    load(WSH.Arguments(0));
    async = false;
    setProperty('SelectionLanguage', 'XPath');
}

if (DOM.parseError.errorCode) {
   WSH.Echo(DOM.parseError.reason);
   WSH.Quit(1);
}

for (var d = DOM.documentElement.selectNodes('//Name/text()'), i = 0; i < d.length; i++) {
    WSH.Echo(d[i].data);
}

答案 2 :(得分:1)

批处理文件与要处理的数据格式密切相关。如果数据发生更改,通常需要新的批处理文件。下面的纯批处理文件只要该行少于8190个字符,就会提取示例未格式化的xml文件的名称。

@echo off
setlocal EnableDelayedExpansion

for /F "delims=" %%a in (contacts.xml) do (
   set "line=%%a"
   for %%X in (^"^
% Do NOT remove this line %
^") do for /F "delims=" %%b in ("!line:>=%%~X!") do (
      if /I "!field!" equ "<Name" for /F "delims=<" %%c in ("%%b") do echo %%c
      set "field=%%b"
   )
)