Xml 在定义的字符串后查找特定字符串

Xml 在定义的字符串后查找特定字符串,xml,powershell,batch-file,Xml,Powershell,Batch File,我正在尝试基于.xml文件为已安装的库生成.txt报告。 它应该报告库SNPID号|库名称|注册表项|库路径。按升序编号排序,最后对齐列 主要问题是,当.xml文件只有一个SNPID和一个名称时,脚本可以工作,但当.xml包含多个SNPID和名称时,脚本不能工作 一些提示: .xml文件中搜索的字符串/行始终具有附加空格 SNPID也可以有字母。 在里面我们可以有多个 在里面我们可以有多个 顺序始终相同,名称为1: 但是Name/SNPID可以在内部,也可以在内部 当里面有价值时,所有口味的产品

我正在尝试基于.xml文件为已安装的库生成.txt报告。 它应该报告库SNPID号|库名称|注册表项|库路径。按升序编号排序,最后对齐列

主要问题是,当.xml文件只有一个SNPID和一个名称时,脚本可以工作,但当.xml包含多个SNPID和名称时,脚本不能工作

一些提示:

.xml文件中搜索的字符串/行始终具有附加空格 SNPID也可以有字母。 在里面我们可以有多个 在里面我们可以有多个 顺序始终相同,名称为1: 但是Name/SNPID可以在内部,也可以在内部 当里面有价值时,所有口味的产品注册码都是一样的。 这是我到目前为止的代码

@echo off
pushd "%~dp0"
setlocal
set "Backup_Folder=%~dp0NI_Backup"
set "SNPID_List=%Backup_Folder%\SNPID_Report.txt"
set "SNPID_TMP_List_To_Order=%Backup_Folder%\SNPID_TMP_List_To_Order.txt"
set "SNPID_TMP_List_To_Realign=%Backup_Folder%\SNPID_TMP_List_To_Realign.txt"
set "XML_Dir=C:\Program Files\Common Files\Native Instruments\Service Center"
set "Registry_Key=HKLM\SOFTWARE\Native Instruments"
if not exist "%Backup_Folder%" ( mkdir "%Backup_Folder%" >nul 2>&1 )
setlocal EnableDelayedExpansion
REM Loop through .xml
(
    for /f "delims=" %%a in ('dir /s/b/a-d "%XML_Dir%\*.xml"^| find /v "NativeAccess" ^| find /v "ProductHints" ^| find /v "Maschine 2"') do (
        for /f "usebackqtokens=1-3delims=<>" %%E in ("%%a") do (
            if "%%F"=="SNPID" (
                for /f "usebackqtokens=1-3delims=<>" %%I in ("%%a") do (
                    if "%%J"=="Name" (
                        for /f "usebackqtokens=1-3delims=<>" %%M in ("%%a") do (
                            if "%%N"=="RegKey" (
                                for /f  "tokens=2*" %%Q in ('reg query "%Registry_Key%\%%O" /v "ContentDir" 2^>nul ') do (
                                    set "ContentDir=%%R"
                                    if "!ContentDir:~1,2!"==":\" ( echo %%G ^| %%K ^| %Registry_Key%\%%O ^| %%R )
    ))))))))
)>"%SNPID_TMP_List_To_Order%"
REM Rename Paths ending with backslash
call "%~dp0Jrepl.bat" "(.*)\\$" "$1" /xseq /m /f "%SNPID_TMP_List_To_Order%" /o -
REM Remove duplicates
call "%~dp0Jrepl.bat" "\c([\c\r\n]+)\r?\n(?=[\s\S]*\c\1$)" "" /xseq /m /f "%SNPID_TMP_List_To_Order%" /o -
REM echo column title
echo SNPID^| Library Name^| Registry Key^| Library Location>"%SNPID_TMP_List_To_Realign%"
REM Sort by SNPID number
sort <"%SNPID_TMP_List_To_Order%" >>"%SNPID_TMP_List_To_Realign%"
REM Get Columns length
set "SNPID_MaxLength=0"
set "LibName_MaxLength=0"
set "RegKey_MaxLength=0"
for /f "usebackqtokens=1-3 delims=|" %%a in ("%SNPID_TMP_List_To_Realign%") do (
    set "String=%%a" & call :strlen
    for /f "tokens=* delims=0" %%B in ("!result!") do (
        if %%B gtr !SNPID_MaxLength! set "SNPID_MaxLength=%%B"
    )
    set "String=%%b" & call :strlen
    for /f "tokens=* delims=0" %%B in ("!result!") do (
        if %%B gtr !LibName_MaxLength! set "LibName_MaxLength=%%B"
    )
    set "String=%%c" & call :strlen
    for /f "tokens=* delims=0" %%B in ("!result!") do (
        if %%B gtr !RegKey_MaxLength! set "RegKey_MaxLength=%%B"
    )
)
REM Set Columns Spacing
set "Space_Count=%SNPID_MaxLength%"
set "SNPID_Space= "
set "LibName_Space= "
set "RegKey_Space= "

:SNPID_Spacing
if "%Space_Count%"=="0" ( set "Space_Count=%LibName_MaxLength%" & goto :LibName_Spacing )
set "SNPID_Space=%SNPID_Space% "
set /a "Space_Count-=1"
goto :SNPID_Spacing

:LibName_Spacing
if "%Space_Count%"=="0" ( set "Space_Count=%RegKey_MaxLength%" & goto :RegKey_Spacing )
set "LibName_Space=%LibName_Space% "
set /a "Space_Count-=1"
goto :LibName_Spacing

:RegKey_Spacing
if "%Space_Count%"=="0" ( goto :Realign_Columns )
set "RegKey_Space=%RegKey_Space% "
set /a "Space_Count-=1"
goto :RegKey_Spacing

REM Columns Alignment
:Realign_Columns
(
    for /f "usebackqtokens=1-4 delims=|" %%a in ("%SNPID_TMP_List_To_Realign%") do (
        set "SNPID_Aligned=%%a%SNPID_Space%" & set "SNPID_Aligned=!SNPID_Aligned:~0,%SNPID_MaxLength%!"
        set "LibName_Aligned=%%b%LibName_Space%" & set "LibName_Aligned=!LibName_Aligned:~0,%LibName_MaxLength%!"
        set "RegKey_Aligned=%%c%RegKey_Space%" & set "RegKey_Aligned=!RegKey_Aligned:~0,%RegKey_MaxLength%!"
        echo !SNPID_Aligned!^|!LibName_Aligned!^|!RegKey_Aligned!^|%%d
    )
)>"%SNPID_List%"
endlocal
REM del "%SNPID_TMP_List%" "%SNPID_TMP_List_To_Order%" "%SNPID_TMP_List_To_Realign%"
pause & exit /b

:strlen
(
    (set^ tmp=!String!)
    set "len=1"
    for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
        if "!tmp:~%%P,1!" NEQ "" (
            set /a "len+=%%P"
            set "tmp=!tmp:~%%P!"
    ))
)
(
    set "result=!len!"
    exit /b
)

但应仅限于:

165 | Maschine 2
334 | Maschine 2 Essentials
249 | Battery 4
166 | Another Flavour
167 | Another Flavour2

optionally, also
334165166167| Maschine 2
or without... (would like to see both outputs)
意思是:

始终将SNPID与其内部的名称关联,除非内部有值,否则我将SNPID与内部的名称关联

在有或没有味道的情况下省略名字…我需要查看两个不同的解析输出来选择

名称始终在其SNPID编号之上,但中间可能有一些值和不同的行数

当存在风味值时,风味RegKey是产品RegKey

更新: 更新了PS解析的问题尝试,它的工作很好,但我不能解决的味道的事情,太难了我…也不能在UTF8NOBOM输出

"DummyLine" | Out-File "$PSScriptRoot\Parsed_List.txt" -Encoding UTF8
$items = Get-ChildItem "C:\Program Files\Common Files\Native Instruments\Service Center\*.xml"
foreach ($item in $items) {
    [xml]$XML_File = Get-Content $item
    $XML_File.ProductHints.Product | % {
        $Name = $_.Name
        $RegKey = $_.RegKey
        If (-Not $_.SNPID) {$SNPID = "ThirdParty"} Else {$SNPID = $_.SNPID}
        If (-Not $_.Company) {$Company = "Not specified"} Else {$Company = $_.Company}
        If ($SNPID -eq "334165") {$Name = "Maschine 2 Essential";$SNPID = "165"}
        "$SNPID`|$Name`|$Company`|$RegKey`|Location" | Out-File "$PSScriptRoot\Parsed_List.txt" -append -Encoding UTF8
    }
}

你的描述既混乱又不完整。如果一个文件包含多个SNPID和名称,是否要省略一条记录?哪一个?第一个

也许此代码可以帮助您:

@echo off
setlocal

rem Initialize variables
set "i=0"
for /F "delims==" %%a in ('set A_ 2^>NUL') do set "%%a="

rem Process all files
for /F "delims=" %%a in ('dir /S /B /A:-D *.xml') do (

   rem Accumulate records for this file
   setlocal EnableDelayedExpansion
   for /F "usebackq tokens=1-3 delims=<>" %%E in ("%%a") do (
      if "%%F" == "Name" (
         set /A i+=1
         set "A_Name[!i!]=%%G"
      ) else if "%%F" == "RegKey" (
         set "A_RegKey[!i!]=%%G"
      ) else if "%%F" == "SNPID" (
         set "A_SNPID[!i!]=%%G"
         set "A_Order[%%G]=!i!"
         if !i! equ 1 set "first=%%G"
      )
   )

   rem If there are more than 1 records: omit the first one
   if !i! gtr 1 set "A_Order[!first!]="

   rem Show records
   echo ============ File %%a ================
   for /F "tokens=2 delims==" %%i in ('set A_Order[') do (
      echo !A_SNPID[%%i]!   !A_Name[%%i]!
   )
   echo/

   rem Reset all variables
   endlocal

)
pause
我正在尝试基于.xml文件为已安装的库生成.txt报告。它应该报告库SNPID号|库名称|注册表项|库路径。按升数排序

我不太熟悉PowerShell及其功能,但由于批处理的局限性,使用本机批处理函数解析XML是一个非常糟糕的主意。我想您已经亲眼看到了批处理脚本会变得多么复杂。 更糟糕的是,戴夫·本汉姆用“jrepl.bat”完成了惊人的工作,没有冒犯到他

请使用真正的XML解析器,如:

如果我没弄错你的问题,这就是你想要的: -抓取产品以及风味元素节点并按SNPID排序。 -抓住前面提到的兄弟姐妹,加入他们,用|分开

目前,我无法帮助您处理第4个元素| Library Path,因为我没有这些注册表项

…并最终对齐列

这有点困难,但这是可能的。基本上可以归结为: -将上面的输出放在一系列数组中,并分配给一个变量。 -计算每个“列”的最大宽度。 -为每个值添加空白以达到此宽度

xidel -s input.xml --xquery ^"^
  let $a:=for $x in (//Product,//Flavour)^
      order by $x/SNPID^
      return $x/[^
        SNPID,^
        Name,^
        (RegKey,../RegKey)^
      ],^
      $b:=(1 to count($a)) ! max(^
        $a(.) ! string-length()^
      )^
  return^
  $a ! join(^
    for $x at $i in .() return^
    substring(^
      $x^|^|string-join((1 to $b[$i]) ! ' '),^
      1,$b[$i]^
    ),^
    ' ^| '^
  )^
"
165          | Maschine 2 Essentials | Maschine 2
166          | Another Flavour       | Maschine 2
167          | Another Flavour2      | Maschine 2
249          | Battery 4             | Battery
334          | Maschine 2            | Maschine 2
334165166167 | Maschine 2            | Maschine 2
这是一个“修饰”查询,每行末尾和每个|都有必要的转义字符,您可以在命令提示下直接复制粘贴


另请参见。

好的,不要使用批处理文件来解析XML数据,请使用一种语言,例如,本机支持此类数据格式的语言…谢谢,我用powershell更新了问题…它解析正确,但仍在努力解决问题,并以UTF8BOM而不是UTF8输出,所以我需要输出第一个伪行,因为批处理后的第一个字符很奇怪,那么批处理脚本的执行速度也比for/f循环慢。对不起,这是我在这里的第一篇文章……我意识到了这一点。事实上,我不想省略任何名称,除非有值,否则我可能会在更新.xml示例和预期结果之前省略名称和SNPID。无论如何,谢谢你,你的帖子总是很好,可以学到很多东西
165 | Maschine 2
334 | Maschine 2 Essentials
249 | Battery 4
166 | Another Flavour
167 | Another Flavour2

optionally, also
334165166167| Maschine 2
or without... (would like to see both outputs)
"DummyLine" | Out-File "$PSScriptRoot\Parsed_List.txt" -Encoding UTF8
$items = Get-ChildItem "C:\Program Files\Common Files\Native Instruments\Service Center\*.xml"
foreach ($item in $items) {
    [xml]$XML_File = Get-Content $item
    $XML_File.ProductHints.Product | % {
        $Name = $_.Name
        $RegKey = $_.RegKey
        If (-Not $_.SNPID) {$SNPID = "ThirdParty"} Else {$SNPID = $_.SNPID}
        If (-Not $_.Company) {$Company = "Not specified"} Else {$Company = $_.Company}
        If ($SNPID -eq "334165") {$Name = "Maschine 2 Essential";$SNPID = "165"}
        "$SNPID`|$Name`|$Company`|$RegKey`|Location" | Out-File "$PSScriptRoot\Parsed_List.txt" -append -Encoding UTF8
    }
}
@echo off
setlocal

rem Initialize variables
set "i=0"
for /F "delims==" %%a in ('set A_ 2^>NUL') do set "%%a="

rem Process all files
for /F "delims=" %%a in ('dir /S /B /A:-D *.xml') do (

   rem Accumulate records for this file
   setlocal EnableDelayedExpansion
   for /F "usebackq tokens=1-3 delims=<>" %%E in ("%%a") do (
      if "%%F" == "Name" (
         set /A i+=1
         set "A_Name[!i!]=%%G"
      ) else if "%%F" == "RegKey" (
         set "A_RegKey[!i!]=%%G"
      ) else if "%%F" == "SNPID" (
         set "A_SNPID[!i!]=%%G"
         set "A_Order[%%G]=!i!"
         if !i! equ 1 set "first=%%G"
      )
   )

   rem If there are more than 1 records: omit the first one
   if !i! gtr 1 set "A_Order[!first!]="

   rem Show records
   echo ============ File %%a ================
   for /F "tokens=2 delims==" %%i in ('set A_Order[') do (
      echo !A_SNPID[%%i]!   !A_Name[%%i]!
   )
   echo/

   rem Reset all variables
   endlocal

)
pause
============ File C:\Users\Antonio\Documents\ASMB\Modern Batch File Programming\BORRAME\File1.xml ================
249   Battery 4

============ File C:\Users\Antonio\Documents\ASMB\Modern Batch File Programming\BORRAME\File2.xml ================
165   Maschine 2 Essentials
334   Maschine 2
xidel -s input.xml --xquery "for $x in (//Product,//Flavour) order by $x/SNPID return $x/join((SNPID,Name,(RegKey,../RegKey)),' | ')"
165 | Maschine 2 Essentials | Maschine 2
166 | Another Flavour | Maschine 2
167 | Another Flavour2 | Maschine 2
249 | Battery 4 | Battery
334 | Maschine 2 | Maschine 2
334165166167 | Maschine 2 | Maschine 2
xidel -s input.xml --xquery ^"^
  let $a:=for $x in (//Product,//Flavour)^
      order by $x/SNPID^
      return $x/[^
        SNPID,^
        Name,^
        (RegKey,../RegKey)^
      ],^
      $b:=(1 to count($a)) ! max(^
        $a(.) ! string-length()^
      )^
  return^
  $a ! join(^
    for $x at $i in .() return^
    substring(^
      $x^|^|string-join((1 to $b[$i]) ! ' '),^
      1,$b[$i]^
    ),^
    ' ^| '^
  )^
"
165          | Maschine 2 Essentials | Maschine 2
166          | Another Flavour       | Maschine 2
167          | Another Flavour2      | Maschine 2
249          | Battery 4             | Battery
334          | Maschine 2            | Maschine 2
334165166167 | Maschine 2            | Maschine 2