Найти конкретную строку после определенной строки - PullRequest
0 голосов
/ 19 октября 2019

Я пытаюсь сгенерировать .txt отчет на основе .xml файлов для установленных библиотек. Должен сообщить номер библиотеки SNPID |Название библиотеки |Ключ реестра |Путь к библиотеке. Сортировка по возрастанию и, наконец, выравнивание столбцов.

Основная проблема заключается в том, что скрипт работает, когда в файле .xml есть только один SNPID и одно имя, но не в том случае, если в файле XML есть несколько SNPID и имен

Некоторые советы:

  • Найденные строки / строки в файлах .xml ВСЕГДА имеют добавляющие пробелы
  • SNPID также может содержать буквы.
  • Внутри <producthint> </producthint> у нас может быть несколько <product>
  • Внутри <product> </product> у нас может быть несколько <flavour> </flavour>
  • . порядок всегда одинаковый, имя 1-е: <Name></Name> <SNPID></SNPID>
  • Но имя / SNPID может быть либо внутри <product> </product>, либо внутри <flavour> </flavour>
  • Когда в <product> есть значение <flavour>, RegKey продукта одинаков для всех разновидностей.

Вот мой код ...

@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
)

(я упростилXML-файлы здесь)

<?xml version="1.0" encoding="UTF-8"?>
<ProductHints>
  <Product version="3">
    <Name>Battery 4</Name>
    <Company>Company Name</Company>
    <some value>xxx</some value>
    <RegKey>Battery</RegKey>
    <some value>yyy</some value>
    <BingName>Battery 4</BingName>
    <SNPID>249</SNPID>
  </Product>
</ProductHints>

даст:

249 | Battery 4 | Battery | PATH

, в то время как

<?xml version="1.0" encoding="UTF-8"?>
<ProductHints>
  <Product version="3">
    <Name>Maschine 2</Name>
    <Company>Company Name</Company>
    <SNPID>334165166167</SNPID>
    <RegKey>Maschine 2</RegKey>
    <Flavour>
      <Name>Maschine 2</Name>
      <SNPID>334</SNPID>
      <Value>0</Value>
    </Flavour>
    <Flavour>
      <Name>Maschine 2 Essentials</Name>
      <Value>-1</Value>
      <SNPID>165</SNPID>
    </Flavour>
    <Flavour>
      <Name>Another Flavour</Name>
      <SNPID>166</SNPID>
      <some value>yyy</some value>
    </Flavour>
    <Flavour>
      <Name>Another Flavour2</Name>
      <some value>yyy</some value>
      <SNPID>167</SNPID>
    </Flavour>
  </Product>
  <Product version="3">
    <Name>Battery 4</Name>
    <Company>Company Name</Company>
    <some value>xxx</some value>
    <RegKey>Battery</RegKey>
    <some value>yyy</some value>
    <BingName>Battery 4</BingName>
    <SNPID>249</SNPID>
  </Product>
</ProductHints>

даст:

165    | Maschine 2
166    | Maschine 2
167    | Maschine 2
334    | Maschine 2
249    | Maschine 2           
165    | Maschine 2 Essentials
166    | Maschine 2 Essentials
167    | Maschine 2 Essentials
334    | Maschine 2 Essentials
249    | Maschine 2 Essentials
165    | Another Flavour
166    | Another Flavour
167    | Another Flavour
334    | Another Flavour
249    | Another Flavour
etc...

, нодолжно быть только:

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 с его ИМЯ внутри <Product> </Product>, если только внутри <Product></Product> нет значения <flavour>, тогда я ассоциируюSNPID с ИМЯ, которое находится внутри <flavour> </flavour>.

Пропуск первого ИМЯ в случае, если есть вкус, или нет ... Мне нужно было бы посмотреть два разных проанализированных вывода, чтобы выбрать.

NAME всегда выше своего номера SNPIDно между ними может быть несколько значений (и разное количество строк)

Когда присутствует значение ароматизатора, аромат RegKey равен Product 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
    }
}

1 Ответ

0 голосов
/ 23 октября 2019

Ваше описание сбивает с толку и неполное. Если файл содержит несколько SNPID и Имен, хотите ли вы пропустить одну запись? Который из? first one?

Возможно, этот код может вам помочь:

@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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...