【问题标题】:Get all strings between a specific tag in an unformatted XML file with a batch file使用批处理文件获取未格式化的 XML 文件中特定标记之间的所有字符串
【发布时间】:2015-03-26 12:02:34
【问题描述】:

我正在尝试获取 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(这是它的生成方式)在 1 行时,我只能得到名字

<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 文件?

【问题讨论】:

  • 删除for,并将您的文件视为单行(无论是否使用单个环境变量和goto重复直到找到&lt;Name&gt;。顺便说一句经过辩论是否可以/应该使用正则表达式来解析 HTML/XML...我们将进入下一步...批处理文件!;) 大声笑说真的,您只能在非常受控的情况下执行此操作。空名称可能是&lt;Name/&gt;,字符串可能包含&amp;character;,或者可能有CDATA(至少)。
  • 嗨,阿德里亚诺,感谢您的解释,但我需要更多细节,我对这个主题不是很熟练。
  • 此处用于拆分:stackoverflow.com/a/14621732/1207195 并读取文件stackoverflow.com/q/15481078/1207195(仅两个示例!不一定是最好的示例)。请注意,它们没有解决我提到的其他问题,因此您可能需要手动完成。作为选项...您是否考虑过从批处理文件调用的 vbscript/jscript 脚本?
  • 感谢阿德里亚诺的资源,目前我无法在这个系统中使用除原生批处理之外的任何其他工具。

标签: xml string parsing batch-file


【解决方案1】:

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

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

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

假设您从未嵌套过 &lt;Name&gt; 元素,则可以在大多数简单场景下使用以下 JREPL.BAT 命令解析您的姓名。但与任何正则表达式“解决方案”一样,此代码并非适用于所有情况。

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

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

【讨论】:

  • 感谢您的出色解释,看来我无法用纯批处理来做到这一点。目前我无法向系统添加任何实用程序,但我会尽快尝试您的解决方案。
【解决方案2】:

在我回答之前,我应该指出您的单行 XML 缺少一个 &lt;/Row&gt; 关闭标记,并且所有 &lt;Name&gt; 元素都包含 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 查询来选择所有 &lt;Name&gt; 节点的文本子节点——基本上,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);
}

【讨论】:

  • 非常好!一种适当的,强大的方法来做到这一点。比我使用正则表达式要好得多。
  • 太棒了。关于解析/编辑 XML 有很多问题。一个常用的工具将减轻很多人的生活。计划创建一个但最近我没有太多空闲时间。 MSXML2.XMLHTTP 对象也是相当不错的选择,但 DOM 解析器更好。
  • 感谢 Rojo,我修复了 1 行 XML。这似乎是一个很好的解决方案,我只知道这方面的基础知识。但我会试试看,很好地描述了问题。
  • @carlos:只是好奇,你试过这个脚本吗?是什么最终让您选择了 Aacini 的解决方案?
  • 好吧,问题是我不能在这个系统中使用任何其他东西,只能使用纯批处理,而且 Aacini 的解决方案效果很好,我会尽快尝试使用你的解决方案,因为它看起来很合适方法。
【解决方案3】:

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

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

编辑添加了一些解释

此解决方案使用了一个有趣的技巧,即用换行符替换字符串中的字符(ASCII 10)字符,然后将结果传递给for /F 命令。这样,由这种字符分隔的原始字符串部分将作为单独的行处理。

这是这种方法最简单的例子:

@echo off
setlocal EnableDelayedExpansion

set "line=Line one|Line two|Line three|Line four"

for %%X in (^"^
% Do NOT remove this line %
^") do for /F "delims=" %%b in ("!line:|=%%~X!") do echo %%b
)

第一个for %%X 是将换行 字符分配给%%X 可替换参数的方法。之后,!line:|=%%~X! 部分用于将每个 | 字符替换为换行符。最后,第二个for /F 命令以通常的方式处理生成的

【讨论】:

  • 感谢 Aacini,使用本机批处理,此解决方案完美运行。不过,我将不得不考虑 8190 字节的限制。
  • @Aacini:你能教我这个脚本的含义吗?它的任何工作方式,但有兴趣了解工作
猜你喜欢
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-26
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多