Don Rolling
Don Rolling

Reputation: 2339

PowerShell parse xml and save changes

I'm parsing a csproj file for a nuget install and I've got a node that needs to be altered. The node in question is the node named "Generator" where it's value equals "TextTemplatingFileGenerator" and it's parent node has an attribute of "WebConfigSettingsGeneratorScript.tt" (the second part isn't in here yet).

Here's the script that I've got, but it's not quite done. It's working, but it saves an empty file. Also, it doesn't have the 2nd part of my where clause, which is

$path = 'C:\Projects\Intouch\NuGetTestPackage\NuGetTestPackage'
cd $path
$files = get-childitem -recurse -filter *.csproj
foreach ($file in $files){
    ""
    "Filename: {0}" -f $($file.Name)
    "=" * ($($file.FullName.Length) + 10)   

    if($file.Name -eq 'NuGetTestPackage1.csproj'){
        $xml = gc $file.FullName | 
        Where-Object { $_.Project.ItemGroup.None.Generator -eq 'TextTemplatingFileGenerator' } | 
        ForEach-Object { $_.Project.ItemGroup.None.Generator = '' }
        Set-Content $file.FullName $xml
    }   
}

Here's a basic version of the XML:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <None Include="T4\WebConfigSettingGeneratorScript.tt">
      <Generator>TextTemplatingFileGenerator</Generator>
      <LastGenOutput>WebConfigSettingGeneratorScript.txt</LastGenOutput>
    </None>

Thanks a lot. I'm a total PowerShell n00b!

Upvotes: 11

Views: 42753

Answers (3)

Fran&#231;ois Racine
Fran&#231;ois Racine

Reputation: 21

OK, now my change is working:

    $fileName = “C:\sovgarde\updates.xml”;
$xml = [System.Xml.XmlDocument](Get-Content $fileName);

$child = $xml.CreateElement('option')
$child.SetAttribute('name', 'CHECK_NEEDED')
$child.SetAttribute('value','false')
If ($xml.application.component.option.name -icontains "CHECK_NEEDED") {
    
    $xml.SelectNodes("//option[@name=`"CHECK_NEEDED`"]") | % {$_.ParentNode.removechild($_) }
    #$xml.Save($fileName)   
    
}
$node = $xml.SelectSingleNode('//component')
$node.AppendChild($child)
$xml.Save($fileName)

Upvotes: 0

Keith Hill
Keith Hill

Reputation: 201692

As @empo says, you need to cast the output of gc $file.FullName to [xml] e.g. $xml = [xml](gc $file.FullName). And then after making the change but before looping to the next file, you need to save the file e.g. $xml.Save($file.FullName).

This works with the sample project you provided:

$file = gi .\test.csproj
$pattern = 'TextTemplatingFileGenerator'
$xml = [xml](gc $file)
$xml | Where {$_.Project.ItemGroup.None.Generator -eq $pattern} |
       Foreach {$_.Project.ItemGroup.None.Generator = ''}
$xml.Save($file.Fullname)

Upvotes: 30

Emiliano Poggi
Emiliano Poggi

Reputation: 24826

Are you missing a cast?

$xml = [xml] gc $file.FullName

Upvotes: 5

Related Questions