返回列表 发帖

[文本处理] 【已解决】求助批处理从一堆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>COPY
我需要用一个批处理,把所有文件中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 6250000COPY
1

评分人数

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

本帖最后由 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=
    )
)
pauseCOPY

TOP

回复 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
)
pauseCOPY

TOP

优化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
pauseCOPY

TOP

本帖最后由 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/bCOPY

TOP

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

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

TOP

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

QQ 20147578

TOP

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

TOP

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

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

TOP

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


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

TOP

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

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

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-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"
)
pauseCOPY
要显示的内容我都做了特殊标记。
2.这个问题你需要补习一下变量设置方面的知识,还是举一个例子来自己观察一下吧:
@echo off
setlocal enabledelayedexpansion
for /l %%i in (1,1,9) do (
    set str=!str!,%%i
    echo,!str!
)
pauseCOPY
请观察每次循环,变量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,
)
pauseCOPY

TOP

回复 13# qixiaobin0715


   太感谢了,马上学习

TOP

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

评分人数

TOP

返回列表