标题: [文本处理] 【已解决】求助批处理从一堆XML中提取关键词写到csv中 [打印本页]
作者: zhengwei007 时间: 2024-9-19 09:41 标题: 【已解决】求助批处理从一堆XML中提取关键词写到csv中
本帖最后由 zhengwei007 于 2024-9-21 08:52 编辑
我有一堆文件名乱起的XML文件,文件中内容大致为以下内容:- <?xml version="1.0" encoding="UTF-8"?>
- <list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../xsd/skillTrees.xsd">
- <!-- Arcana Lord -->
- <skillTree type="classSkillTree" classId="96" parentClassId="14">
- <!-- Confirmed CT2.5 and Updated to H5 -->
- <skill skillName="Wisdom" skillId="328" skillLevel="1" getLevel="76" levelUpSp="6250000" learnedByNpc="true" />
- <!-- Forgotten Scrolls -->
- <skill skillName="Spirit of the Cat" skillId="929" skillLevel="1" getLevel="83" learnedByFS="true" />
- <!-- HighFive new -->
- <skill skillName="Dimension Spiral" skillId="1558" skillLevel="15" getLevel="76" levelUpSp="6250000" learnedByNpc="true" />
- </skillTree>
- </list>
复制代码
我需要用一个批处理,把所有文件中skill skillName等字段全部单独挑出来,每个字段前都加上classId="96",我写下执行完的结果:- classID skillName skillId skillLevel getLevel levelUpSp
- 96 Wisdom 328 1 76 12500000
- 96 Spirit of the Cat 929 1 83
- 96 Dimension Spiral 1558 15 76 6250000
复制代码
作者: qixiaobin0715 时间: 2024-9-19 12:52
本帖最后由 qixiaobin0715 于 2024-9-19 13:35 编辑
classID与其它字段不在一行,并且它们之间可能会有其它无效行的干扰(虽然也进行了粗略筛选),调试时稍微复杂一些:- @echo off
- setlocal enabledelayedexpansion
- set BoxHead=classId skillName skillId skillLevel getLevel levelUpSp
- for %%i in (%BoxHead%) do set %%i=true
- echo,%BoxHead%
- for /f "delims=" %%i in ('findstr "skill" *.xml') do (
- set n=
- set NewLine=!classId!
- for %%j in (%%i) do (
- if /i "!str!"=="classId" (
- set NewLine=%%~j
- set classId=%%~j
- ) else if defined !str! (
- set NewLine=!NewLine! %%~j
- set n=1
- )
- set "str=%%~j"
- )
- if defined n (
- echo,!NewLine!
- set NewLine=
- )
- )
- pause
复制代码
作者: ppll2030 时间: 2024-9-19 14:41
回复 1# zhengwei007
代码保存为bat文件,跟xml放一起,运行后会生成与xml同名的csv文件。- @echo off &setlocal enabledelayedexpansion
- for /f "delims=" %%i in ('dir /b /a-d *.xml') do (
- (set "v="&echo classID, skillName, skillId, skillLevel, getLevel, levelUpSp
- for /f tokens^=1-10^ delims^=^ ^=^<^" %%a in (' findstr "=" "%%i" ') do (
- if /i "%%a"=="skillTree type" (set "v1=%%d")
- if /i "%%a"=="skill skillName" (
- set "v=!v1!, %%b, %%d, %%f, %%h"
- if /i "%%j" neq "true" (echo !v!, %%j) else echo !v!
- )
- ))>%%~ni.csv
- )
- pause
复制代码
作者: qixiaobin0715 时间: 2024-9-20 09:34
优化2楼代码,并把分隔符修改为逗号:- @echo off
- setlocal enabledelayedexpansion
- set BoxHead=classId,skillName,skillId,skillLevel,getLevel,levelUpSp
- for %%i in (%BoxHead%) do set %%i=true
- (echo,%BoxHead%
- for /f "delims=" %%i in ('findstr "skill" *.xml') do (
- for %%j in (%%i) do (
- if /i "!str!"=="classId" (
- set classId=%%~j
- ) else if defined !str! (
- set NewLine=!NewLine!,%%~j
- )
- set "str=%%~j"
- )
- if defined NewLine (
- echo,!classId!!NewLine!
- set NewLine=
- )
- ))>out.csv
- pause
复制代码
作者: aloha20200628 时间: 2024-9-20 11:13
本帖最后由 aloha20200628 于 2024-9-20 11:15 编辑
回复 1# zhengwei007
当前目录中的所有 *.xml 目标文件根据楼主提取要求及其输出格式汇总为一个结果文件 all.csv
- @echo off &(echo,classID skillName skillId skillLevel getLevel levelUpSp
- for %%F in (*.xml) do for /f tokens^=1-10^delims^=^" %%a in ('findstr /ic:" skillname=" "%%F" ') do (
- set/p="96 %%b %%d %%f %%h"<nul
- if /i "%%j" neq "true" (echo, %%j) else (echo,)
- ))>all.csv
- pause&exit/b
复制代码
作者: qixiaobin0715 时间: 2024-9-20 11:44
本帖最后由 qixiaobin0715 于 2024-9-20 11:51 编辑
实际上上面代码考虑的都不是太全面,看到楼主的示范文本,好像数据有缺失的情况,后面数据缺失问题不大,如果中间缺上一个,比如skillLevel的数据缺失,就会出问题,顺序如果不同也会出问题,那样的话,数据上下就会错位。还是要想一想别的办法。
作者: czjt1234 时间: 2024-9-20 12:36
建议把 skillName 放在最后一列,否则不能对齐,要用英文的逗号作分隔符输出 csv 文件
作者: 77七 时间: 2024-9-20 12:52
数据还是很规整的,只是写起来比较啰嗦...- @echo off
- cd /d "%~dp0"
- set list=classId skillName skillId skillLevel getLevel levelUpSp
- set "_list=%list:* =%"
- (
- echo %list: =,%
- setlocal enabledelayedexpansion
- for /f "tokens=1* delims=:" %%i in ('findstr /i "%list: == %" *.xml') do (
- set str=%%j
- set "str=!str:/=!"
- set "str=!str:<=!"
- set "str=!str:>=!"
- for %%a in (%_list%) do (
- set _%%a=,
- )
- set _str=
- for %%a in (!str!) do (
- if "%%a" equ "%%~a" (
- set b=%%a
- ) else (
- set _!b!=%%a
- )
- )
- for %%a in (%_list%) do (
- set _str=!_str!,!_%%a!
- )
- if "!_str:,=!" neq "" (
- echo !_classId!,!_str:~1!
- )
- )
- endlocal
- ) > out.csv
- pause
- exit
复制代码
作者: qixiaobin0715 时间: 2024-9-20 13:09
本帖最后由 qixiaobin0715 于 2024-9-20 13:20 编辑
兼容中间数据缺失及数据顺序不同的处理思路有了,总觉得楼主一直在看热闹。估计楼主的文件不存在我说的情况,上面大家的代码已足够处理数据,算了,不费脑子了。
作者: zhengwei007 时间: 2024-9-21 08:52
兼容中间数据缺失及数据顺序不同的处理思路有了,总觉得楼主一直在看热闹。估计楼主的文件不存在我说的情况 ...
qixiaobin0715 发表于 2024-9-20 13:09
为什么这么说呢?今天周末我才来看下,楼上的已经实现了我要的功能,大家都很厉害。
作者: qixiaobin0715 时间: 2024-9-22 08:46
本帖最后由 qixiaobin0715 于 2024-9-22 08:57 编辑
在不在线,好像大家都能看到,虽然说显示有所滞后。多说没用,算我没说。
作者: delab-1 时间: 2024-9-25 20:17
本帖最后由 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%中的指标匹配上的。
多谢大神解释哈
作者: qixiaobin0715 时间: 2024-9-26 09:11
本帖最后由 qixiaobin0715 于 2024-9-26 09:52 编辑
回复 12# delab-1
还是以实例自己来观察的好。
1.把代码第7行的for循环摘出来,改造成易于理解的形式。在下面代码中,我需要提取b的值“2”,应当如何处理呢?可以在最后面设置变量str,使之延后显示,也就是说当变量str的值等于“b”时,下一个循环中,%%~i的值就是"2",示范代码如下:- @echo off
- setlocal enabledelayedexpansion
- for %%i in (a="1" b="2" c="3") do (
- echo,!str!
- echo,%%~i
- if /i "!str!"=="b" (
- set b=%%~i
- echo,********* b=%%~i
- )
- echo,---------------------
- echo,
- set "str=%%~i"
- )
- pause
复制代码
要显示的内容我都做了特殊标记。
2.这个问题你需要补习一下变量设置方面的知识,还是举一个例子来自己观察一下吧:- @echo off
- setlocal enabledelayedexpansion
- for /l %%i in (1,1,9) do (
- set str=!str!,%%i
- echo,!str!
- )
- pause
复制代码
请观察每次循环,变量str值的变化情况。
3.把前面2个问题搞清楚了,这个问题仔细想一想,也就差不多能够想通了。
关于第1条所说的“延后显示”的问题,这里也给出一个实例代码,每组显示中,前一行 为变量重新设置前的值,后一行 为变量重新设置后的值,看看是否是错位显示:- @echo off
- setlocal enabledelayedexpansion
- for /l %%i in (1,1,5) do (
- echo,!str!
- set str=%%i
- echo,!str!
- echo,-------------
- echo,
- )
- pause
复制代码
作者: delab-1 时间: 2024-9-26 09:42
回复 13# qixiaobin0715
太感谢了,马上学习
作者: qixiaobin0715 时间: 2024-9-26 10:15
下面代码更通用一些,适合于出现数据部分缺失及顺序不同的情况,而得到的结果中数据也不会错位:- @echo off
- set BoxHead=classId,skillName,skillId,skillLevel,getLevel,levelUpSp
- for %%i in (%BoxHead%) do set _%%i=true
- echo,%BoxHead%
- for /f "tokens=2* delims=: " %%i in ('findstr /i "<skill" *.xml') do (
- if /i "%%i"=="<skillTree" (
- for %%k in (%%j) do (
- if defined n set "classId=%%~k"&set n=
- if "%%k"=="classId" set n=1
- )
- ) else (
- setlocal enabledelayedexpansion
- for %%k in (%%j) do (
- if defined _!str! set !str!=%%~k&set m=1
- set str=%%k
- )
- if defined m echo,!classId!,!skillName!,!skillId!,!skillLevel!,!getLevel!,!levelUpSp!&set m=
- endlocal
- )
- )
- pause
复制代码
作者: aloha20200628 时间: 2024-9-26 12:11
本帖最后由 aloha20200628 于 2024-9-26 12:13 编辑
去年至今已有但多帖是从网页数据中提取指定字段的题型,本来可以用 vbs/jscript/powershell 先将网页经过 xml 格式转换工具处理,再按字段名批量提取,但此法要求源网页格式须严格符合 xml 规范,故对大量没有严格‘守法’的网页容易出现兼容性问题,对此还真不如 findstr+for/f 组合版来的简明痛快,即先用 findstr 小正则‘粗洗’网页,再用 for/f ‘精切’ 字段,findstr 的正则匹配度越高,留给批处的处理量就越少,for/f 分割器的切口越准,提取目标字段的效率越高 ... 当然此法也有短处,一旦遭遇数据行长度超过8k字符量的实况就会‘罢工’。
作者: delab-1 时间: 2024-9-27 20:57
回复 15# qixiaobin0715
非常感谢,在学习测试中,太感谢啦
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |