Modify XML Parent Attributes iterating through Child attributes using powershell

后端 未结 2 1526
北海茫月
北海茫月 2020-12-20 08:15

So I have the following xml (items.xml) and I want to find the attributes of the child node item iterate through the attributes and if I find similar attributes at parent no

相关标签:
2条回答
  • 2020-12-20 09:17

    You can get parent element from an attribute via OwnerElement property. So this is one possible way to get the desired output :

    $model.SelectNodes("//item/@*") |
        ForEach {
            # set attributes value on `model` element
            $_.OwnerElement.ParentNode.ParentNode.SetAttribute($_.LocalName, $_.Value)
            # remove attributes except `name` from `item` element
            If ($_.LocalName -ne "name") { $_.OwnerElement.RemoveAttribute($_.LocalName) }
        }
    
    0 讨论(0)
  • 2020-12-20 09:17

    Since your title mentions Modify XML, consider XSLT, the special purpose language designed solely to transform XML files. Specifically, you can run the Identity Transform (copy document as is) and then keep only the attributes that match attribute names of ancestor::model (grandparent) using the <xsl:when> and <xsl:otherwise> conditionals. PowerShell can create an object of .NET Framework class, System.Xml.Xsl.XslCompiledTransform, to run XSLT 1.0 scripts.

    XSLT (save as .xsl to be passed as argument in PowerShell)

    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output version="1.0" encoding="UTF-8" indent="yes" method="xml"/>
    <xsl:strip-space elements="*"/>
    
      <!-- Identity Transform -->
      <xsl:template match="@*|node()">
         <xsl:copy>
           <xsl:apply-templates select="@*|node()"/>
         </xsl:copy>
      </xsl:template>
    
      <!-- Conditionally Keep Item Attributes -->
      <xsl:template match="item/@*[name()!='name']">    
         <xsl:variable name="item_attr" select="name()"/>        
         <xsl:choose>
           <xsl:when test="ancestor::model/@*[name()=$item_attr]"/>          
           <xsl:otherwise><xsl:copy/></xsl:otherwise>
         </xsl:choose>    
      </xsl:template>
    
    </xsl:transform>
    

    PowerShell (general script for any XML input and XSLT 1.0 script)

    param ($xml, $xsl, $output)
    
    if (-not $xml -or -not $xsl -or -not $output) {
        Write-Host "& .\xslt.ps1 [-xml] xml-input [-xsl] xsl-input [-output] transform-output"
        exit;
    }
    
    trap [Exception]{
        Write-Host $_.Exception;
    }
    
    $xslt = New-Object System.Xml.Xsl.XslCompiledTransform;
    
    $xslt.Load($xsl);
    $xslt.Transform($xml, $output);
    
    Write-Host "generated" $output;
    
    Read-Host -Prompt "Press Enter to exit";
    

    Command line call

    Powershell.exe -File "C:\Path\To\PowerShell\Script.ps1"^
     "C:\Path\To\Input.xml" "C:\Path\To\XSLTScript.xsl" "C:\Path\To\Ouput.xml"
    

    Output

    <?xml version="1.0" encoding="utf-8"?>
    <items>
      <model type="model1" name="default" price="12.12" date="some_value">
        <PriceData>
          <item name="watch" />
        </PriceData>
      </model>
      <model type="model2" name="default" price="12.12" date="some_value">
        <PriceData>
          <item name="toy" />
        </PriceData>
      </model>
      <model type="model3" name="default" price="12.12" date="some_value">
        <PriceData>
          <item name="bread" />
        </PriceData>
      </model>
    </items>
    
    0 讨论(0)
提交回复
热议问题