【问题标题】:How to parse xml file in batch (CMD)如何批量解析xml文件(CMD)
【发布时间】:2012-06-13 11:55:32
【问题描述】:

你能帮我列出这个文件中的浏览器吗 http://techpatterns.com/downloads/firefox/useragentswitcher.xml 成txt文件,用%tab%分隔符分隔?

应该有 3 或 4 列:

1) 示例数据中的文件夹描述:<folder description="Browsers - Windows">

2) 示例数据中的浏览器类型:<folder description="Legacy Browsers">

3) 示例数据中的用户代理:<useragent description="Avant Browser 1.2" useragent="Avant Browser/1.2.789rel1 (http://www.avantbrowser.com)" app

在这里我看到第一个问题,因为某些浏览器不在文件夹 <folder description="Legacy Browsers">" 中,而是在 <separator/>

所以第一列应该定义系统,第二列是类型,第三列是浏览器。

下一个问题是 Devises 文件夹包含一个文件夹。

@echo off 
Setlocal EnableDelayedExpansion
SET file=useragentswitcher.xml
SET delim="

FOR /F "tokens=* skip=1" %%F IN (!file!) DO (
  REM echo %%F
  call :parse "%%F" > temp.txt
  FOR /F "tokens=1,2,3,4,5,6,7 skip=1 delims=" %%A IN (temp.txt) DO (
    IF "%%A"=="folder" (
      SET /A level=!level!+1
      echo Level:!level!
      ) ELSE IF "%%A"=="/folder" (
          SET /A level=!level!-1
          echo Level:!level!
        )

   echo A:%%A
  )
  pause
)

exit /b

:parse
Setlocal EnableDelayedExpansion
  SET A=%*
  REM REMOVE double paranthesis and <> 
  SET A=!A:~2,-2!
  REM replace double qoutes
  SET A=!A:"=µ!
  FOR /F "tokens=1,2 delims=µ=" %%A IN ("!A!") DO (
    SET first=%%A
    SET second=%%B
    echo !first!
    FOR /F "tokens=1,2 delims= " %%A IN ("!first!") DO (
      echo %%A
      echo %%B
    )
    echo !second!
  )
endlocal
exit /b

这会解析该行的一个标签,我现在将使用它。

【问题讨论】:

  • 你的代码哪里出错了?我看不到任何编程问题?
  • 我会粘贴代码,如果我有的话。现在我被困在这里:FOR /F "tokens=1,2 delims=^"" %%B IN ("%%A") DO我应该如何使用双引号作为分隔符?
  • 代码已更新,开始使用效果更好。
  • 是否可以将 linefeed 添加为 delim? 我尝试做的是将文件行解析为变量%%A %%B %%C %%D %%E %%F

标签: xml batch-file cmd


【解决方案1】:

看来你应该能找到比批处理更好的工具来解析 XML...

但我相信下面的代码就是您要找的。

由于文件夹的数量不同,我交换了输出中列的顺序。我将浏览器描述放在首位,然后是文件夹,每列一个。这允许固定每列的定义。

我使用 jeb 的答案中的信息将 " 包含为 FOR 分隔符。

编辑 - 我简化了代码

注意 - 第一次尝试是为了处理使用 Internet Explorer 检索到的 XML 副本而编写的。从那以后,我发现 IE 改变了文件的格式。此代码高度依赖于文件的确切格式,因此它不适用于原始 XML。它还作为示例说明为什么批处理是解析 XML 的糟糕选择

@echo off
setlocal enableDelayedExpansion

::Define the files to use - change as needed
set input="test.xml"
set output="result.txt"

::The assignment below should have exactly one TAB character between = and "
set "TAB=   "

set cnt=0
set "folder0="
>%output% (
  for /f usebackq^ tokens^=1^,2^ delims^=^=^" %%A in (%input%) do (
    for %%N in (!cnt!) do (
      if "%%A"=="- <folder description" (
        set /a cnt+=1
        for %%M in (!cnt!) do set "folder%%M=!folder%%N!%TAB%%%B"
      )
      if "%%A"=="  </folder>" (
        set /a cnt-=1
      )
      if "%%A"=="  <useragent description" (
        echo %%B!folder%%N!
      )
    )
  )
)

如果! 出现在任何描述中,代码将失败,因为延迟扩展会破坏包含! 的任何 FOR 变量的扩展。我检查了,您的文件在任何描述中都不包含!

可以修改代码以处理描述中的!,但它会变得更加复杂。它需要打开和关闭延迟扩展,并在 ENDLOCAL 屏障中保存变量值。

以上代码高度依赖于 XML 的格式。如果非标准破折号被删除,或者空白排列发生变化,它将失败。

以下变体更加健壮,但仍要求每一行都包含一个 XML 标记。

@echo off
setlocal enableDelayedExpansion

::Define the files to use - change as needed
set input="test.xml"
set output="result.txt"

::The assignment below should have exactly one TAB character between = and "
set "TAB=   "

set cnt=0
set "folder0="
>%output% (
  for /f usebackq^ tokens^=1^,2^ delims^=^=^" %%A in (%input%) do (
    for %%N in (!cnt!) do (
      set "test=%%A"
      if "!test:<folder description=!" neq "!test!" (
        set /a cnt+=1
        for %%M in (!cnt!) do set "folder%%M=!folder%%N!%TAB%%%B"
      )
      if "!test:</folder>=!" neq "!test!" (
        set /a cnt-=1
      )
      if "!test:<useragent description=!" neq "!test!" (
        echo %%B!folder%%N!
      )
    )
  )
)

编辑 - 最后一个版本

这里有一个可以处理数据中!的版本。我在输出中添加了一个附加列。第一列仍然是浏览器描述。第二列是用户代理字符串。其余列是文件夹。该解决方案使用延迟扩展切换技术。它还使用额外的 FOR /F 来跨 ENDLOCAL 屏障保留变量值。

@echo off
setlocal disableDelayedExpansion

::Define the files to use - change as needed
set input="test.xml"
set output="result.txt"

::The assignment below should have exactly one TAB character between = and "
set "TAB=   "

set cnt=0
set folder0=""
>%output% (
  for /f usebackq^ tokens^=1-4^ delims^=^=^" %%A in (%input%) do (
    set "test=%%A"
    set "desc=%%B"
    set "agent=%%D"
    setlocal enableDelayedExpansion
    for %%N in (!cnt!) do (
      if "!test:<folder description=!" neq "!test!" (
        set /a cnt+=1
        for %%M in (!cnt!) do for /f "delims=" %%E in ("!folder%%N!") do (
          endlocal
          set "folder%%M=%%~E%TAB%%%B"
          set "cnt=%%M"
        )
      ) else if "!test:</folder>=!" neq "!test!" (
        endlocal
        set /a cnt-=1
      ) else if "!test:<useragent description=!" neq "!test!" (
        echo !desc!%TAB%!agent!!folder%%N!
        endlocal
      ) else endlocal
    )
  )
)

【讨论】:

  • 感谢您的代码。查找“!”时不能使用带有延迟变量的字符串替换吗?雅虎!包含这样的字符。但也许我们可以在解析开始之前用不同的字符替换感叹号。我也尝试了一些代码,你可以看到我更新了有问题的代码。我在那里有问题,因为我保存解析值的 temp.txt 中的每个值都在单独的行中。是否可以将 temp.txt 中的每一行读取到变量 %%A %%B %%C 等?
  • 这是什么? set "folder0=" &gt;%output% ( for ?我第一次看到所以不明白它是做什么的。
  • @user1141649 - 使用您提供的数据,如果您关心用户代理字符串,您只需要担心!。我假设您只需要浏览器描述。无法使用 FOR 将多行读入 %%A %%B 等,如您所愿。但你不应该首先需要临时文件。
  • @user1141649 - 我需要保证 folder0 的初始值才能使算法正常工作。大 FOR 语句周围带有重定向的括号用于捕获文件中的结果。我认为这就是你最终想要的。在循环外进行一次重定向比在循环内使用附加模式更有效。
  • @user1141649 - 我添加了一个保留! 值的最终解决方案。
【解决方案2】:

检查xpath.bat - 可以通过给定的xpath表达式从xml获取值的脚本:

call xpath.bat "useragentswitcher.xml" "//folder/@description"

【讨论】:

    【解决方案3】:

    回复你的评论How should I use double quotes as delimiter?

    只需使用表格

    FOR /F tokens^=1^,2^ delims^=^" %%B IN ("%%A") DO
    

    这是如何工作的?
    通常不能将引号字符用作分隔符。
    这是唯一已知的解决方法,重要的是缺少围绕 FOR/F 选项的 正常 引号。
    但必须将选项仅解析为一个标记,因此您需要转义所有标准批处理解析器分隔符(空格制表符 =,;)。
    引号不是批处理分隔符,但也需要转义,以避免行的其余部分被引用,然后解析器将失败。
    但是您可以将^" 更改为"",因为第二个引号将被忽略。

    FOR /F tokens^=1^,2^ delims^="" %%B IN ("%%A") DO ...
    

    【讨论】:

    • 你能解释一下它是如何工作的吗?对我来说,这看起来像是混乱的角色。为什么标记被 ^^ 包围而分隔符没有被包围?真的很困惑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-30
    • 1970-01-01
    • 2013-12-17
    • 1970-01-01
    • 1970-01-01
    • 2021-02-11
    • 1970-01-01
    相关资源
    最近更新 更多