在XML中搜索值并将其覆盖

时间:2019-05-07 07:57:58

标签: xml powershell

我需要在XML文件中找到功能部件的值,并在与“ if”子句匹配的情况下用另一个值覆盖它。

有数百个称为“功能”的标签,每个标签都有相同的参数,但值不同。我在浏览标签时遇到了麻烦,因为我无法在“功能”标签之间进行区分。

这是打印机驱动程序的配置文件,大约有10000行。 这只是XML的一小部分。我需要检查

的值
<current_option>AUTO</current_option>

与“ PLAIN”不同,如果这样,我必须用“ PLAIN”覆盖它。在这种情况下,我应该用“普通”覆盖“自动”。

我需要查找和更改的标签位于以下结构中:

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

您可以在1022行的此屏幕截图中找到它:

Structure of the 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 个答案:

答案 0 :(得分:1)

这将找到所有值不等于ind_COUNTRY CODE的标签current_option

PLAIN

请注意,标记和值在XPath中区分大小写。

答案 1 :(得分:0)

您可以在引用$ file的循环中使用它:

(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部分。

答案 2 :(得分:0)

注意:不清楚是只匹配AUTO个值,还是只匹配 not 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' }

以下解决方案基于您自己的解决方案尝试,但是会变慢:

您只需要扩展whereWhere-Object)过滤器脚本块即可检查current_option元素的值,如果匹配,则使用{{1}更新该元素}(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

答案 3 :(得分:0)

如果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