[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

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

本帖最后由 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
复制代码
1

评分人数

    • Batcher: 感谢给帖子标题标注[已解决]字样PB + 2

回复 15# qixiaobin0715


    非常感谢,在学习测试中,太感谢啦

TOP

本帖最后由 aloha20200628 于 2024-9-26 12:13 编辑

去年至今已有但多帖是从网页数据中提取指定字段的题型,本来可以用 vbs/jscript/powershell 先将网页经过 xml 格式转换工具处理,再按字段名批量提取,但此法要求源网页格式须严格符合 xml 规范,故对大量没有严格‘守法’的网页容易出现兼容性问题,对此还真不如 findstr+for/f 组合版来的简明痛快,即先用 findstr 小正则‘粗洗’网页,再用 for/f ‘精切’ 字段,findstr 的正则匹配度越高,留给批处的处理量就越少,for/f 分割器的切口越准,提取目标字段的效率越高 ... 当然此法也有短处,一旦遭遇数据行长度超过8k字符量的实况就会‘罢工’。

TOP

下面代码更通用一些,适合于出现数据部分缺失及顺序不同的情况,而得到的结果中数据也不会错位:
  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

评分人数

TOP

回复 13# qixiaobin0715


   太感谢了,马上学习

TOP

本帖最后由 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
复制代码

TOP

本帖最后由 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%中的指标匹配上的。

    多谢大神解释哈

TOP

本帖最后由 qixiaobin0715 于 2024-9-22 08:57 编辑

在不在线,好像大家都能看到,虽然说显示有所滞后。多说没用,算我没说。

TOP

兼容中间数据缺失及数据顺序不同的处理思路有了,总觉得楼主一直在看热闹。估计楼主的文件不存在我说的情况 ...
qixiaobin0715 发表于 2024-9-20 13:09


为什么这么说呢?今天周末我才来看下,楼上的已经实现了我要的功能,大家都很厉害。

TOP

本帖最后由 qixiaobin0715 于 2024-9-20 13:20 编辑

兼容中间数据缺失及数据顺序不同的处理思路有了,总觉得楼主一直在看热闹。估计楼主的文件不存在我说的情况,上面大家的代码已足够处理数据,算了,不费脑子了。

TOP

数据还是很规整的,只是写起来比较啰嗦...
  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
复制代码
bat小白,请多指教!谢谢!

TOP

建议把 skillName 放在最后一列,否则不能对齐,要用英文的逗号作分隔符输出 csv 文件

QQ 20147578

TOP

本帖最后由 qixiaobin0715 于 2024-9-20 11:51 编辑

实际上上面代码考虑的都不是太全面,看到楼主的示范文本,好像数据有缺失的情况,后面数据缺失问题不大,如果中间缺上一个,比如skillLevel的数据缺失,就会出问题,顺序如果不同也会出问题,那样的话,数据上下就会错位。还是要想一想别的办法。

TOP

本帖最后由 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
复制代码

TOP

优化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
复制代码

TOP

返回列表