0

I have an XML file, which looks like the following:

<ViewsFile>
 <Categories>
  <ViewCategory Name="General">
   <Views>
    <View Name="firstView">
     ...
    </View>
    <View Name="secondView">
     ...
    </View>
   </Views>
  </ViewCategory>
  <ViewCategory Name="Bookings">
   <Views>
    <View Name="firstView">
     ...
    </View>
    <View Name="secondView">
     ...
    </View>
   </Views>
  </ViewCategory>
<ViewCategory Name="Activities">
   <Views>
    <View Name="firstView">
     ...
    </View>
   </Views>
  </ViewCategory>
 </Categories>
</ViewsFile>

Now I want to append the following XML file to the first one, taking into account the correct position, namely the parent with the name 'Bookings':

<ViewCategory Name="Bookings">
 <Views>
  <View Name="newView">
   ...
  </View>
 </Views>
</ViewCategory>

So the final XML file should look like this:

<ViewsFile>
 <Categories>
  <ViewCategory Name="General">
   <Views>
    <View Name="firstView">
     ...
    </View>
    <View Name="secondView">
     ...
    </View>
   </Views>
  </ViewCategory>
  <ViewCategory Name="Bookings">
   <Views>
    <View Name="firstView">
     ...
    </View>
    <View Name="secondView">
     ...
    </View>
    <View Name="newView">
    ...
    </View>
   </Views>
  </ViewCategory>
<ViewCategory Name="Activities">
   <Views>
    <View Name="firstView">
     ...
    </View>
   </Views>
  </ViewCategory>
 </Categories>
</ViewsFile>

My PowerShell script at the moment looks like this:

[xml] $x = Get-Content C:\Users\user\Desktop\exitingViews.xml;
[xml] $y = Get-Content C:\Users\user\Desktop\newView.xml;

$x.ViewsFile.Categories.ViewCategory.Views.AppendChild($x.ImportNode(($y.ViewCategory.Views.View), $true));
$x.Save('C:\Users\user\Desktop\final.xml'); 

But it only appends the new view to the last category.

Is there any 'easy' possibility to define, where to append the child node?

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
Gardinero
  • 331
  • 2
  • 13

1 Answers1

3

When you use PowerShell's convenient adaptation of the XML DOM provided by System.Xml.XmlDocument, the . operator performs member-access enumeration, which means that access such as .ViewCategories will return all child elements by that name.

You therefore need to filter the .ViewCategories array to get the specific element of interest, which you can do with the .Where() array method (PSv4+):

$x.ViewsFile.Categories.ViewCategory.Where({ $_.Name -eq 'Bookings' }).Views.AppendChild($x.ImportNode(($y.ViewCategory.Views.View), $true))

Alternatively, use an XPath query to locate the element of interest, via .SelectSingleNode():

$x.SelectSingleNode('//ViewCategory[@Name = "Bookings"]').Views.AppendChild($x.ImportNode(($y.ViewCategory.Views.View), $true))

Note: I've taken a shortcut with //, which locates ViewCategoy elements anywhere in the document, but you can spell out the whole path as /ViewsFile/Categories/ViewCategory[@Name = "Bookings"], which is faster and avoids ambiguity.

mklement0
  • 382,024
  • 64
  • 607
  • 775