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