How to Add Data to an XML File Using Windows PowerShell

Hey, Scripting Guy! QuestionHey, Scripting Guy! I need to be able to use Windows PowerShell to add data to an XML file. Unfortunately, there is no Add-XML cmdlet available. I thought about using the Windows PowerShell Add-Content cmdlet and trying to write my data to the file, but it never worked correctly. I never could get all of those angle thingies to line up properly. There has got to be a better way to do this, but after spending several hours Binging around on the Internet I finally gave up, and decided to write you. — JS

Hey, Scripting Guy! AnswerHello JS, Microsoft Scripting Guy Ed Wilson here. It is amazing how quickly things change. It reminds me of the weather when I was in Lisbon, Portugal. The saying was if you did not like the weather, just wait a few minutes and it will change. The sunsets were stunning. I enjoyed walking along the waterfront and took the following photo on one of those walks. Photo Ed took of sunset in Lisbon JS, I was thinking about creating a here-string that would contain the elements for an XML file, substitute values for the variables contained in the here-string, and then write that to a file. However, as I thought about it, I decided it might be error prone. I then thought about using the methods from the system.xml.xmldocument .NET Framework class to add elements and childnodes to an existing XML document. However, that ended up being too complicated. So I decided to cheat. The complete Add-XmlContentToFile.ps1 Windows PowerShell script is shown here. Add-XmlContentToFile.ps1

$path = “C:\fso\books.xml”
$csvPath = “C:\fso\books.csv”
$doc = [xml](Get-Content -Path $path)
foreach($e in (Import-Csv -Path $csvPath))
{
 $element = $Doc.catalog.book[0].clone()
 $element.id = $e.id
 $element.author = $e.author
 $element.title = $e.title
 $element.genre = $e.genre
 $element.price = $e.price
 $element.publish_date = $e.publish_date
 $element.description = $e.description
 $doc.DocumentElement.AppendChild($element)
}
$doc.Save(“C:\fso\x.xml”)

To illustrate adding content to an XML file, I am going to use the books.xml file that I copied from MSDN. The books.xml file contains a number of books and stores some important information about each book, such as author, title, price, and genre. This is shown in XML Notepadin the following image. Image of books.xml file in XML Notepad

The source code for the books.xml file is not as pretty as that shown in XML Notepad. You can open the file in Internet Explorer, but it is little better than Notepad, as shown in the following image. Image of books.xml file in Notepad The data that must be added to the books.xml file is contained in a CSV file named books.csv. The contents of books.csv are shown in the following image. Image of contents of books.csv file The first thing the Add-XMLContentToFile.ps1 script does, after creating a couple of variables to hold the path to the XML file and to the CSV file, is use the Get-Content cmdlet to read the XML file, and to use the [xml] type accelerator to convert the contents into an XML document. This is shown here: $doc=[xml](Get-Content-Path$path)

Piping the $doc variable to the Get-Member cmdlet confirms that you are now working with an instance of the System.XML.XMLDocument .NET Framework class. You can access the different elements of the books.xml file by using the same dotted notation you would use to work with any other object. The first node is catalog. This is shown here: PSC:\>$doc=[xml](Get-contentc:\fso\books.xml)
PSC:\>$doc

xml catalog
— ——-
version=”1.0″ catalog

PSC:\>$doc.catalog

book
—-
{book,book,book,book…}

PSC:\>

Because the books are returned in an array, you can index directly into the array: PSC:\>$doc.catalog.book[0]

id :bk101
author :Gambardella,Matthew
title :XMLDeveloper’s Guide
genre : Computer
price : 44.95
publish_date : 2000-10-01
description : An in-depth look at creating applications
with XML.

PS C:\>

Piping the book element to Get-Member reveals that each book is an instance of the System.Xml.XmlElement .NET Framework class. This is shown here:

PS C:\> $doc.catalog.book[0] | Get-Member

TypeName: System.Xml.XmlElement

Name MemberType Definition
—- ———- ———-
ToString CodeMethod static string XmlNode(psobject instance)
AppendChild Method System.Xml.XmlNode AppendChild(System….
Clone Method System.Xml.XmlNode Clone()
CloneNode Method System.Xml.XmlNode CloneNode(bool deep)
CreateNavigator Method System.Xml.XPath.XPathNavigator Create…
Equals Method bool Equals(System.Object obj)
GetAttribute Method string GetAttribute(string name), stri…
GetAttributeNode Method System.Xml.XmlAttribute GetAttributeNo…
GetElementsByTagName Method System.Xml.XmlNodeList GetElementsByTa…
GetEnumerator Method System.Collections.IEnumerator GetEnum…
GetHashCode Method int GetHashCode()
GetNamespaceOfPrefix Method string GetNamespaceOfPrefix(string pre…
GetPrefixOfNamespace Method string GetPrefixOfNamespace(string nam…
GetType Method type GetType()
HasAttribute Method bool HasAttribute(string name), bool H…
InsertAfter Method System.Xml.XmlNode InsertAfter(System….
InsertBefore Method System.Xml.XmlNode InsertBefore(System…
Normalize Method System.Void Normalize()
PrependChild Method System.Xml.XmlNode PrependChild(System…
RemoveAll Method System.Void RemoveAll()
RemoveAllAttributes Method System.Void RemoveAllAttributes()
RemoveAttribute Method System.Void RemoveAttribute(string nam…
RemoveAttributeAt Method System.Xml.XmlNode RemoveAttributeAt(i…
RemoveAttributeNode Method System.Xml.XmlAttribute RemoveAttribut…
RemoveChild Method System.Xml.XmlNode RemoveChild(System….
ReplaceChild Method System.Xml.XmlNode ReplaceChild(System…
SelectNodes Method System.Xml.XmlNodeList SelectNodes(str…
SelectSingleNode Method System.Xml.XmlNode SelectSingleNode(st…
SetAttribute Method System.Void SetAttribute(string name, …
SetAttributeNode Method System.Xml.XmlAttribute SetAttributeNo…
Supports Method bool Supports(string feature, string v…
WriteContentTo Method System.Void WriteContentTo(System.Xml….
WriteTo Method System.Void WriteTo(System.Xml.XmlWrit…
Item ParameterizedProperty System.Xml.XmlElement Item(string name…
author Property System.String author {get;set;}
description Property System.String description {get;set;}
genre Property System.String genre {get;set;}
id Property System.String id {get;set;}
price Property System.String price {get;set;}
publish_date Property System.String publish_date {get;set;}
title Property System.String title {get;set;}

PS C:\>

The XmlElement class has a clone method that can be used to copy an entire XmlElement and store the copy in a variable. The values associated with each of the attributes of the element can then be modified directly, and the newly created and modified element can be written back to the XmlDocument. A new XmlElement will need to be created for each item that exists in the CSV file. To read the CSV file, use the Import-Csv cmdlet. This portion of the script is shown here:

foreach($ein(Import-Csv-Path$csvPath))

{

$element=$Doc.catalog.book[0].clone()

EachattributeoftheclonedXmlElementispatchedwiththeappropriatefieldfromtheCSVfile.Asimpleassignmentoperatorisused,asshownhere:

$element.id=$e.id

$element.author=$e.author

$element.title=$e.title

$element.genre=$e.genre

$element.price=$e.price

$element.publish_date=$e.publish_date

$element.description=$e.description

After the attributes of the XmlElement have been filled out from the CSV file, the appendChild method is used to add the data in the newly created XmlElement to the XmlDocument. This is shown here: $doc.DocumentElement.AppendChild($element)

}

ToavoidmessinguptheoriginalXMLfile,Isaveitwithadifferentname:

$doc.Save("C:\fso\x.xml")

The newly created file, x.xml, is shown in the following image. Image of newly created file in Notepad

JS, that is all there is to using Windows PowerShell to write XML information. This also brings to a close our String Week articles. Join us tomorrow for Quick-Hits Friday. We invite you to follow us on Twitter and Facebook. If you have any questions, send email to us at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace. Ed Wilson and Craig Liebendorfer, Scripting Guys

0 comments

Comments are closed. Login to edit/delete your existing comments