找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 41200|回复: 16

[文本处理] 【已解决】求助批处理从一堆XML中提取关键词写到csv中

[复制链接]
发表于 2024-9-19 09:41:33 | 显示全部楼层 |阅读模式
本帖最后由 zhengwei007 于 2024-9-21 08:52 编辑

我有一堆文件名乱起的XML文件,文件中内容大致为以下内容:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../xsd/skillTrees.xsd">
  3.         <!-- Arcana Lord -->
  4.         <skillTree type="classSkillTree" classId="96" parentClassId="14">
  5.                 <!-- Confirmed CT2.5 and Updated to H5 -->
  6.                 <skill skillName="Wisdom" skillId="328" skillLevel="1" getLevel="76" levelUpSp="6250000" learnedByNpc="true" />
  7.                 <!-- Forgotten Scrolls -->
  8.                 <skill skillName="Spirit of the Cat" skillId="929" skillLevel="1" getLevel="83" learnedByFS="true" />
  9.                 <!-- HighFive new -->
  10.                 <skill skillName="Dimension Spiral" skillId="1558" skillLevel="15" getLevel="76" levelUpSp="6250000" learnedByNpc="true" />
  11.         </skillTree>
  12. </list>
复制代码
我需要用一个批处理,把所有文件中skill skillName等字段全部单独挑出来,每个字段前都加上classId="96",我写下执行完的结果:

  1. classID        skillName        skillId        skillLevel        getLevel        levelUpSp
  2. 96        Wisdom        328        1        76        12500000
  3. 96        Spirit of the Cat        929        1        83       
  4. 96        Dimension Spiral        1558        15        76        6250000
复制代码

评分

参与人数 1PB +2 收起 理由
Batcher + 2 感谢给帖子标题标注[已解决]字样

查看全部评分

发表于 2024-9-19 12:52:24 | 显示全部楼层
本帖最后由 qixiaobin0715 于 2024-9-19 13:35 编辑

classID与其它字段不在一行,并且它们之间可能会有其它无效行的干扰(虽然也进行了粗略筛选),调试时稍微复杂一些:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set BoxHead=classId        skillName        skillId        skillLevel        getLevel        levelUpSp
  4. for %%i in (%BoxHead%) do set %%i=true
  5. echo,%BoxHead%
  6. for /f "delims=" %%i in ('findstr "skill" *.xml') do (
  7.     set n=
  8.     set NewLine=!classId!
  9.     for %%j in (%%i) do (
  10.         if /i "!str!"=="classId" (
  11.             set NewLine=%%~j
  12.             set classId=%%~j
  13.         ) else if defined !str! (
  14.             set NewLine=!NewLine!        %%~j
  15.             set n=1
  16.         )
  17.         set "str=%%~j"
  18.     )
  19.     if defined n (
  20.         echo,!NewLine!
  21.         set NewLine=
  22.     )
  23. )
  24. pause
复制代码
发表于 2024-9-19 14:41:44 | 显示全部楼层
回复 1# zhengwei007


    代码保存为bat文件,跟xml放一起,运行后会生成与xml同名的csv文件。
  1. @echo off &setlocal enabledelayedexpansion
  2. for /f "delims=" %%i in ('dir /b /a-d *.xml') do (
  3.         (set "v="&echo classID, skillName, skillId, skillLevel, getLevel, levelUpSp
  4.         for /f tokens^=1-10^ delims^=^        ^=^<^" %%a in (' findstr "=" "%%i" ') do (
  5.                 if /i "%%a"=="skillTree type" (set "v1=%%d")
  6.                 if /i "%%a"=="skill skillName" (
  7.                         set "v=!v1!, %%b, %%d, %%f, %%h"
  8.                         if /i "%%j" neq "true" (echo !v!, %%j) else echo !v!
  9.                 )
  10.         ))>%%~ni.csv
  11. )
  12. pause
复制代码
发表于 2024-9-20 09:34:40 | 显示全部楼层
优化2楼代码,并把分隔符修改为逗号:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set BoxHead=classId,skillName,skillId,skillLevel,getLevel,levelUpSp
  4. for %%i in (%BoxHead%) do set %%i=true
  5. (echo,%BoxHead%
  6. for /f "delims=" %%i in ('findstr "skill" *.xml') do (
  7.     for %%j in (%%i) do (
  8.         if /i "!str!"=="classId" (
  9.             set classId=%%~j
  10.         ) else if defined !str! (
  11.             set NewLine=!NewLine!,%%~j
  12.         )
  13.         set "str=%%~j"
  14.     )
  15.     if defined NewLine (
  16.         echo,!classId!!NewLine!
  17.         set NewLine=
  18.     )
  19. ))>out.csv
  20. pause
复制代码
发表于 2024-9-20 11:13:28 | 显示全部楼层
本帖最后由 aloha20200628 于 2024-9-20 11:15 编辑

回复 1# zhengwei007

当前目录中的所有 *.xml 目标文件根据楼主提取要求及其输出格式汇总为一个结果文件 all.csv

  1. @echo off &(echo,classID        skillName        skillId        skillLevel        getLevel        levelUpSp
  2. for %%F in (*.xml) do for /f tokens^=1-10^delims^=^" %%a in ('findstr /ic:" skillname=" "%%F" ') do (
  3.     set/p="96        %%b        %%d        %%f        %%h"<nul
  4.     if /i "%%j" neq "true" (echo,        %%j) else (echo,)
  5. ))>all.csv
  6. pause&exit/b
复制代码
发表于 2024-9-20 11:44:58 | 显示全部楼层
本帖最后由 qixiaobin0715 于 2024-9-20 11:51 编辑

实际上上面代码考虑的都不是太全面,看到楼主的示范文本,好像数据有缺失的情况,后面数据缺失问题不大,如果中间缺上一个,比如skillLevel的数据缺失,就会出问题,顺序如果不同也会出问题,那样的话,数据上下就会错位。还是要想一想别的办法。
发表于 2024-9-20 12:36:01 | 显示全部楼层
建议把 skillName 放在最后一列,否则不能对齐,要用英文的逗号作分隔符输出 csv 文件
发表于 2024-9-20 12:52:15 | 显示全部楼层
数据还是很规整的,只是写起来比较啰嗦...
  1. @echo off
  2. cd /d "%~dp0"
  3. set list=classId skillName skillId skillLevel getLevel levelUpSp
  4. set "_list=%list:* =%"
  5. (
  6.         echo %list: =,%
  7.         setlocal enabledelayedexpansion
  8.         for /f "tokens=1* delims=:" %%i in ('findstr /i "%list: == %" *.xml') do (
  9.                 set str=%%j
  10.                 set "str=!str:/=!"
  11.                 set "str=!str:<=!"
  12.                 set "str=!str:>=!"
  13.                 for %%a in (%_list%) do (
  14.                         set _%%a=,
  15.                 )
  16.                 set _str=
  17.                 for %%a in (!str!) do (
  18.                         if "%%a" equ "%%~a" (
  19.                                 set b=%%a
  20.                         ) else (
  21.                                 set _!b!=%%a
  22.                         )
  23.                 )
  24.                 for %%a in (%_list%) do (
  25.                         set _str=!_str!,!_%%a!
  26.                 )
  27.                 if "!_str:,=!" neq "" (
  28.                         echo !_classId!,!_str:~1!
  29.                 )
  30.         )
  31.         endlocal
  32. ) > out.csv
  33. pause
  34. exit
复制代码
发表于 2024-9-20 13:09:33 | 显示全部楼层
本帖最后由 qixiaobin0715 于 2024-9-20 13:20 编辑

兼容中间数据缺失及数据顺序不同的处理思路有了,总觉得楼主一直在看热闹。估计楼主的文件不存在我说的情况,上面大家的代码已足够处理数据,算了,不费脑子了。
 楼主| 发表于 2024-9-21 08:52:00 | 显示全部楼层
兼容中间数据缺失及数据顺序不同的处理思路有了,总觉得楼主一直在看热闹。估计楼主的文件不存在我说的情况 ...
qixiaobin0715 发表于 2024-9-20 13:09


为什么这么说呢?今天周末我才来看下,楼上的已经实现了我要的功能,大家都很厉害。
发表于 2024-9-22 08:46:42 | 显示全部楼层
本帖最后由 qixiaobin0715 于 2024-9-22 08:57 编辑

在不在线,好像大家都能看到,虽然说显示有所滞后。多说没用,算我没说。
发表于 2024-9-25 20:17:13 | 显示全部楼层
本帖最后由 delab-1 于 2024-9-25 20:37 编辑

回复 4# qixiaobin0715


    大神,可否较为清晰地帮助解释一下命令过程,没有看太懂
例如,1)在命令中,if /i "!str!=="classid" (, set str=%%~j是出现在后面程序中的,这样写可以吗?
         2) set Newline=!Newline!,%%j的作用是什么,为何要在在%%j之前放上!Newline!
         3) 没有搞清楚!str!是如何在取值上如何循环的,因为仅仅看到一个 "!str!=="classid", 后面如何和定义的%BoxHead%中的指标匹配上的。

    多谢大神解释哈
发表于 2024-9-26 09:11:27 | 显示全部楼层
本帖最后由 qixiaobin0715 于 2024-9-26 09:52 编辑

回复 12# delab-1
还是以实例自己来观察的好。
1.把代码第7行的for循环摘出来,改造成易于理解的形式。在下面代码中,我需要提取b的值“2”,应当如何处理呢?可以在最后面设置变量str,使之延后显示,也就是说当变量str的值等于“b”时,下一个循环中,%%~i的值就是"2",示范代码如下:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for %%i in (a="1" b="2" c="3") do (
  4.     echo,!str!
  5.     echo,%%~i
  6.     if /i "!str!"=="b" (
  7.         set b=%%~i
  8.         echo,*********  b=%%~i
  9.     )
  10.     echo,---------------------
  11.     echo,
  12.     set "str=%%~i"
  13. )
  14. pause
复制代码
要显示的内容我都做了特殊标记。
2.这个问题你需要补习一下变量设置方面的知识,还是举一个例子来自己观察一下吧:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /l %%i in (1,1,9) do (
  4.     set str=!str!,%%i
  5.     echo,!str!
  6. )
  7. pause
复制代码
请观察每次循环,变量str值的变化情况。
3.把前面2个问题搞清楚了,这个问题仔细想一想,也就差不多能够想通了。


关于第1条所说的“延后显示”的问题,这里也给出一个实例代码,每组显示中,前一行 为变量重新设置前的值,后一行 为变量重新设置后的值,看看是否是错位显示:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /l %%i in (1,1,5) do (
  4.     echo,!str!
  5.     set str=%%i
  6.     echo,!str!
  7.     echo,-------------
  8.     echo,
  9. )
  10. pause
复制代码
发表于 2024-9-26 09:42:45 | 显示全部楼层
回复 13# qixiaobin0715


   太感谢了,马上学习
发表于 2024-9-26 10:15:58 | 显示全部楼层
下面代码更通用一些,适合于出现数据部分缺失及顺序不同的情况,而得到的结果中数据也不会错位:
  1. @echo off
  2. set BoxHead=classId,skillName,skillId,skillLevel,getLevel,levelUpSp
  3. for %%i in (%BoxHead%) do set _%%i=true
  4. echo,%BoxHead%
  5. for /f "tokens=2* delims=:         " %%i in ('findstr /i "<skill" *.xml') do (
  6.     if /i "%%i"=="<skillTree" (
  7.         for %%k in (%%j) do (
  8.             if defined n set "classId=%%~k"&set n=
  9.             if "%%k"=="classId" set n=1
  10.         )
  11.     ) else (
  12.         setlocal enabledelayedexpansion
  13.         for %%k in (%%j) do (
  14.             if defined _!str! set !str!=%%~k&set m=1
  15.             set str=%%k
  16.         )
  17.         if defined m echo,!classId!,!skillName!,!skillId!,!skillLevel!,!getLevel!,!levelUpSp!&set m=
  18.         endlocal
  19.     )
  20. )
  21. pause
复制代码

评分

参与人数 1技术 +1 收起 理由
Batcher + 1 乐于助人

查看全部评分

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-17 18:41 , Processed in 0.013939 second(s), 8 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表