Поиск значений в XML и их перезапись - PullRequest
0 голосов
/ 07 мая 2019

Мне нужно найти значение функции в файле XML и перезаписать его другим значением, если оно соответствует предложению «if».

Существуют сотни тегов, которые называются «признаками», и каждый из них имеет одинаковые параметры с разными значениями. У меня проблемы с навигацией по тегам, потому что я не могу различить теги "feature".

Это файл конфигурации драйвера принтера, который содержит около 10000 строк. Это небольшая часть XML. Мне нужно проверить, если значение

<current_option>AUTO</current_option>

отличается от «PLAIN», в этом случае я должен перезаписать его «PLAIN». В этом случае я должен перезаписать «AUTO» на «PLAIN».

Тег, который мне нужно найти и изменить, находится в этой структуре:

$ xml.device.software.component.factory.printing.feature [0] .option 1 .feature [5] .current_option

Вы можете найти его на этом скриншоте в строке 1022:

Структура XML

<feature resource_id="550" caption_id="10017" typical="TRUE">
  Media_Type
  <current_option>AUTO</current_option>
  <option resource_id="558"> AUTO </option>
  <option resource_id="559"> PLAIN </option>
  <option resource_id="40551">HP_MATTE_90G</option>
  <option resource_id="30595"> LIGHT </option>
  <option resource_id="566"> BOND </option>
  <option resource_id="567"> RECYCLED </option>
  <option resource_id="30646">HP_LJC_MATTE_105G</option>
  <option resource_id="40552">HP_LJPREM_CHOICE_120G</option>
  <option resource_id="30649">HP_PRES_SOFT_GLOSS_120G</option>
  <option resource_id="10140">HP_PRES_GLOSS_130G</option>
  <option resource_id="30598"> MIDWEIGHT_96_110G </option>
  <option resource_id="30622"> HEAVY </option>
  <option resource_id="30599"> GLOSS </option>
  <option resource_id="30633"> HEAVY_GLOSSY </option>
  <option resource_id="10141">HP_CLJ_BROCHURE_MATTE_160G</option>
  <option resource_id="10142">HP_CL_BROC_GLOSSY_160G</option>
  <option resource_id="30624"> EXTRA_HEAVY </option>
  <option resource_id="30625"> EXTRA_HEAVY_GLOSSY </option>
  <option resource_id="40555">HP_COVER_MATTE_200G</option>
  <option resource_id="10143">HP_CL_PHOTO_GlOSSY_220G</option>
  <option resource_id="30626"> CARDSTOCK176 </option>
  <option resource_id="30615"> CARDGLOSSY </option>
  <option resource_id="562">TRANSPARENCY</option>
  <option resource_id="574"> LABELS </option>
  <option resource_id="561"> LETTERHEAD </option>
  <option resource_id="551"> ENVELOPE </option>
  <option resource_id="560"> PREPRINTED </option>
  <option resource_id="564"> PREPUNCHED </option>
  <option resource_id="30617"> COLOR </option>
</feature>
</option>
<option resource_id="5281">
SeparatorPageAlt
<constraint> CheckHPJobSeparatorPageInstalled </constraint>
<feature resource_id="5277" caption_id="10162">
  UserName
  <current_option>FALSE</current_option>
  <option resource_id="10"> TRUE </option>
  <option resource_id="9"> FALSE </option>
</feature>
<feature resource_id="5278" caption_id="10163">
  FileName
  <current_option>FALSE</current_option>
  <option resource_id="10"> TRUE </option>
  <option resource_id="9"> FALSE </option>
</feature>

Я не могу получить значение «AUTO», чтобы проверить, соответствует ли оно предложению «if»

Вот что я пробовал:

$xml = [xml](Get-Content $Config.FullName)
$xml2 = $xml.device.software.component.factory.printing.feature |
        where {$_.resource_id -eq "550"}

или

$xml2 = $xml | Where-Object {$_.current_option -eq "AUTO"}

или

$xml2 = $xml | Select-Xml -XPath "//feature[@resource_id='550']/current_oprion"

Ответы [ 4 ]

1 голос
/ 07 мая 2019

При этом будут найдены все теги current_option со значением, не равным PLAIN

[xml]$xml = Get-Content $Config.FullName
$notplain=$xml | Select-Xml -XPath "//current_option[.!='PLAIN']"

Обратите внимание, что теги и значения чувствительны к регистру в XPath.

0 голосов
/ 07 мая 2019

Это худший ответ, если объект или файл XML верны.Но это работает, если предоставленная структура XML остается недействительной:

$y = Get-Content z.xml
$resourceLines = ($y | select-string -pattern '<feature resource_id="550"' -SimpleMatch -AllMatches).LineNumber
$optionLines = ($y | select-string -pattern '<current_option>AUTO</current_option>' -SimpleMatch -AllMatches).LineNumber
$featureEndLines = ($y | select-string -pattern '</feature>' -SimpleMatch -AllMatches).LineNumber

foreach ($resourceLine in $resourceLines) {
    $begin = $resourceLine
    $end = $featureEndLines.where({$_ -gt $resourceLine},'First')[0]
    $optionLines.where({$_ -gt $begin -and $_ -lt $end}) |% { $y[($_-1)] = $y[($_-1)] -replace "AUTO","PLAIN" }
}

$y | Set-Content z.xml
0 голосов
/ 07 мая 2019

Примечание: неясно, хотите ли вы соответствовать только значениям AUTO или любому значению, которое не PLAIN;если последнее, используйте current_option[.!='PLAIN'] и $_.current_option -ne 'PLAIN' ниже.

Самый простой и эффективный способ - использовать методы [xml] (System.Xml.XmlDocument) напрямую, используя расширенную версиюВаш запрос XPath также проверяет значение элемента current_option:

$n = $xml.SelectSingleNode("//feature[@resource_id='550']/current_option[.='AUTO']")
if ($n) { $n.InnerText = 'PLAIN' }

Следующие решения основаны на ваших собственных попытках решения, но они будут медленнее:

Выпросто нужно расширить свой блок сценариев фильтра where (Where-Object), чтобы также проверить значение элемента current_option и, если он совпадает, обновить этот элемент с помощью вызова foreach (ForEach-Object):

$xml.device.software.component.factory.printing.feature |
  Where-Object { $_.resource_id -eq '550' -and $_.current_option -eq 'AUTO' } |
    ForEach-Object { $_.current_option = 'PLAIN' }

Альтернативно, с вашим подходом на основе XPath через Select-Xml (это виртуальный эквивалент решения сверху, но медленнее):

$xml |
  Select-Xml -XPath "//feature[@resource_id='550']/current_option[.='AUTO']" |
    ForEach-Object { $_.Node.InnerText = 'PLAIN' }
0 голосов
/ 07 мая 2019

Вы можете использовать это внутри цикла, который ссылается на файл $:

(Get-Content $file.FullName) | Foreach-Object {$_ -replace '<current_option>AUTO</current_option>', "<current_option>PLAIN</current_option>"} | Set-Content $file.FullName -Encoding unicode

Я предполагаю, что здесь используется кодировка Unicode, если нет, вы можете удалить эту -Encoding unicode часть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...