{"id":1740,"date":"2014-01-03T00:00:00","date_gmt":"2014-01-03T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/powershell-data-basics-xml\/"},"modified":"2019-01-23T16:17:59","modified_gmt":"2019-01-23T16:17:59","slug":"powershell-data-basics-xml","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/powershell-data-basics-xml\/","title":{"rendered":"PowerShell Data Basics: XML"},"content":{"rendered":"<div id=\"pretty\">\n<ul>\n<li><a href=\"#first\">Accessing XML data in PowerShell <\/a>\n<ul>\n<li><a href=\"#second\">Accessing XML with XPath. <\/a><\/li>\n<li><a href=\"#third\">Accessing XML as Objects.<\/a><\/li>\n<li><a href=\"#fourth\">Comparison of XPath and Object Approaches<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#fifth\">Modifying or Creating XML Data<\/a>\n<ul>\n<li><a href=\"#sixth\">Adding XML Data<\/a><\/li>\n<li><a href=\"#seventh\">Using XML for Object Serialization<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>Introduction<\/h2>\n<p>As with any high-level language, <code> \tthe  \tdata<\/code> is at the heart of PowerShell. In the case of PowerShell, this boils down to converting external data\u00a0 into PowerShell objects and vice versa. This is the second of a series of articles that shows you how to <i>import<\/i> almost all of the common data formats you are likely to encounter, and how to <i>export<\/i> to some of them as well. The first article in the series,<a href=\"https:\/\/www.simple-talk.com\/sysadmin\/powershell\/powershell-data-basics-file-based-data\/\"> PowerShell Data Basics: File-Based Data<\/a>, covers a variety of text formats, from fixed-width, variable-width, and ragged-right files to CSV, property lists, INI files, and JSON data, and concludes with a treatment of importing and exporting to Excel. Here we concentrate on getting the most from XML.<\/p>\n<h2 id=\"first\">Accessing XML data in PowerShell<\/h2>\n<p>There are two built-in techniques for working with XML data in PowerShell; the <i>XPath<\/i> approach and the <i>object<\/i> \u00a0dot-notation approach. We&#8217;ll\u00a0 describe and compare these two approaches, and try them out on some sample XML. \u00a0For convenience, all the code examples use this <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ms762271.aspx\">sample XML file<\/a> from MSDN. Figure 1 shows a representation of the schema underlying the file in a concise format (particularly when compared to reading the raw XSD file!), courtesy of Visual Studio&#8217;s <b>XML Schema Explorer<\/b>. From the figure, you&#8217;ll notice that the XML file is a catalog that contains a collection of books. Each book has seven characteristics, \u00a0six of which are child elements and one which is \u00a0a child attribute.<\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1917-img92.jpg\" alt=\"1917-img92.jpg\" \/><\/p>\n<p class=\"caption\">Figure 1 Schema for Microsoft&#8217;s sample XML fileo:p&gt;<\/p>\n<p>To load this sample XML file, you can use any of these:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p>$xdoc = <b> new-object<\/b> System.Xml.XmlDocument<\/p>\n<p>$file = resolve-path(&#8220;.\\sample.xml&#8221;)<\/p>\n<p>$xdoc.load($file)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>[xml] $xdoc = <b> get-content<\/b> &#8220;.\\sample.xml&#8221;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>$xdoc = [xml] (<b>get-content<\/b> &#8220;.\\sample.xml&#8221;)<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u00a0if you would prefer to experiment with immediate XML data rather than load an XML file into an <b>XmlDocument<\/b>, it is simple to do. Merely define your XML as a string and cast it to XML type as we&#8217;ve just done with the <b>Get-Content<\/b> cmdlet for files. Here&#8217;s a portion of the sample XML file with only two books:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">$mydoc = [xml] @\"\r\n&lt;catalog&gt;\r\n\u00a0\u00a0 &lt;book id=\"bk101\"\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;author&gt;Gambardella, Matthew&lt;\/author&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;title&gt;XML Developer's Guide&lt;\/title&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;genre&gt;Computer&lt;\/genre&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;price&gt;44.95&lt;\/price&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;publish_date&gt;2000-10-01&lt;\/publish_date&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;description&gt;An in-depth look at creating applications \r\n\u00a0\u00a0\u00a0\u00a0\u00a0 with XML.&lt;\/description&gt;\r\n\u00a0\u00a0 &lt;\/book&gt;\r\n\u00a0\u00a0 &lt;book id=\"bk102\"\"&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;author&gt;Ralls, Kim&lt;\/author&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;title&gt;Midnight Rain&lt;\/title&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;genre&gt;Fantasy&lt;\/genre&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;price&gt;5.95&lt;\/price&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;publish_date&gt;2000-12-16&lt;\/publish_date&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;description&gt;A former architect battles corporate zombies, \r\n\u00a0\u00a0\u00a0\u00a0\u00a0 an evil sorceress, and her own childhood to become queen \r\n\u00a0\u00a0\u00a0\u00a0\u00a0 of the world.&lt;\/description&gt;\r\n\u00a0\u00a0 &lt;\/book&gt;\r\n&lt;\/catalog&gt;o:p&gt;\r\n\"@\r\n<\/pre>\n<h3 id=\"second\">Accessing XML with XPath<\/h3>\n<p>With the file loaded into an <b>XmlDocument<\/b> object, you can then \u00a0navigate the XML tree with <a href=\"http:\/\/www.w3.org\/TR\/xpath\/\">XPath<\/a>. To select a set of nodes use the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.xml.xmldocument.selectnodes.aspx\">SelectNodes<\/a> method:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p>$xdoc.SelectNodes(&#8220;\/\/author&#8221;)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>#text<\/p>\n<p>&#8212;&#8211;<\/p>\n<p>Gambardella, Matthew\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>Ralls, Kim\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>Corets, Eva\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>Corets, Eva\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>Corets, Eva\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>Randall, Cynthia\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>Thurman, Paula\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>Knorr, Stefan\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>Kress, Peter\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>O&#8217;Brien, Tim\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>O&#8217;Brien, Tim\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>Galos, Mike\u00a0\u00a0<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u00a0Or use <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.xml.xmldocument.selectsinglenode.aspx\">SelectSingleNode<\/a> to return just one node:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p>$xdoc.SelectSingleNode(&#8220;\/\/book[2]&#8221;)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>id\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : bk102<\/p>\n<p>author\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : Ralls, Kim<\/p>\n<p>title\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : Midnight Rain<\/p>\n<p>genre\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : Fantasy<\/p>\n<p>price\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : 5.95<\/p>\n<p>publish_date : 2000-12-16<\/p>\n<p>description\u00a0 : A former architect battles corporate zombies,<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 an evil sorceress, and her own childhood to become queen<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 of the world.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Notice in the first example that there are duplicates. Suppose instead that you want a list of <i>unique<\/i> authors in the catalog. You might think that something like &#8230;<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\t$xdoc.SelectNodes(\"\/\/author\") | select -Unique <\/pre>\n<p><span class=\"style1\">&#8230;<\/span>would work, but it actually returns just the first author&#8217;s name. To understand why that failed, you would need to understand more about the structure of XML documents. The first example actually returned a list of <i>text nodes<\/i> (i.e. <i>not<\/i> a list of text) and the unique filter is operating on that list, looking for element type uniqueness. Since all the items in the collection are text nodes, and so are all the same element type, all nodes beyond the first are therefore considered to be duplicates. The result is that only the first is returned.<\/p>\n<p>What you are really after is the string value of each author node. From the author node you must first access its text node (its first and only child), then the value of that text node (line A in the next example). \u00a0Alternately, you can use a slightly shorter expression with the <b>InnerText<\/b> property (line B). One more variation uses the <b>Select-Xml<\/b> cmdlet \u00a0which avoids \u00a0a method call and so is, in some sense, a more distinctively PowerShell approach (line C). All three lines return the same result.<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p>(A) $xdoc.SelectNodes(&#8220;\/\/author&#8221;) | <b> %<\/b> { $_.FirstChild.Value } | <b> select<\/b> <i> -Unique<\/i><\/p>\n<p>(B) $xdoc.SelectNodes(&#8220;\/\/author&#8221;) | <b> %<\/b> { $_.InnerText } | <b> select<\/b> <i> -Unique<\/i><\/p>\n<p>(C) $xdoc | <b> Select-Xml<\/b> &#8220;\/\/author&#8221; | <b> %<\/b> { $_.Node.InnerText } | <b> select<\/b> <i> -Unique<\/i><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>Gambardella, Matthew<\/p>\n<p>Ralls, Kim<\/p>\n<p>Corets, Eva<\/p>\n<p>Randall, Cynthia<\/p>\n<p>Thurman, Paula<\/p>\n<p>Knorr, Stefan<\/p>\n<p>Kress, Peter<\/p>\n<p>O&#8217;Brien, Tim<\/p>\n<p>Galos, Mike<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u00a0<b>SelectNodes<\/b> and <b>SelectSingleNode<\/b> together give you equivalent functionality to <b>Select-Xml<\/b>. Both support namespaces, which I have not mentioned yet. The two methods both take an \u00a0<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.xml.xmlnamespacemanager.aspx\">XmlNamespaceManager<\/a> as an optional second parameter, while the <b>Select-Xml<\/b> cmdlet takes an optional <b>Namespace<\/b> parameter that specifies your namespaces in a hash table.<\/p>\n<p><b>SelectSingleNode<\/b> returns an <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.xml.xmlnode.aspx\">XmlNode<\/a> and <b>SelectNodes<\/b> returns an <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.xml.xmlnodelist.aspx\">XmlNodeList<\/a>. <b>Select-Xml<\/b>, on the other hand, returns a <a href=\"http:\/\/technet.microsoft.com\/en-us\/library\/microsoft.powershell.commands.selectxmlinfo_members.aspx\"> SelectXmlInfo<\/a> object (or an array of them) and its <b>Node<\/b> property provides access to the underlying node. The example just above illustrates these differences.<\/p>\n<h3 id=\"third\">Accessing XML as Objects<\/h3>\n<p>With the same XmlDocument object from the last section, PowerShell also provides dynamic object support for XML data:\u00a0 This allows you to access XML data as first-class PowerShell objects, requiring neither XPath selector nor familiarity with the details of such things as XML nodes, values or text nodes. Furthermore, you get instant, dynamic Intellisense of your XML schema when you load your XML data! Figure 2 illustrates this for the PowerShell ISE, where you get both <i> selection choices<\/i> and <i>word completion<\/i>, just like with PowerShell native tokens. Notice particularly in the bottom expansion that it looks for what you have typed <i>anywhere<\/i> in the property name, not just starting from the first character: Intellisense would find you a date property here whether it is named <b>published_date<\/b> or <b>releaseDate<\/b> or <b>date_of_publication<\/b>. Note that you have word completion available in PowerShell V2 or V3, and in PowerShell ISE or PowerShell console. But selection choices are <i>only<\/i> available in PowerShell ISE in V3.<\/p>\n<p class=\"illustration\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1917-img8E.jpg\" alt=\"1917-img8E.jpg\" \/><\/p>\n<p class=\"caption\">Figure 2 Automatic Intellisense upon loading an XML document<\/p>\n<p>\u00a0Here are some examples to show that the XML is indeed auto-converted to PowerShell objects:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p>$xdoc<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>xml\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 catalog<\/p>\n<p>&#8212;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8212;&#8212;-<\/p>\n<p>version=&#8221;1.0&#8243;\u00a0\u00a0\u00a0\u00a0 catalog<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>$xdoc.catalog<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>book\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>&#8212;-\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>{book, book, book, book&#8230;}\u00a0\u00a0\u00a0\u00a0<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>$xdoc.catalog.book | <b>Format-Table<\/b> <i> -AutoSize<\/i><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>id\u00a0\u00a0\u00a0 author\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 title\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 genre\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 price publish_date description\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>&#8212;\u00a0\u00a0\u00a0 &#8212;&#8212;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8212;&#8211;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8212;&#8211;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8212;&#8211; &#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8211;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>bk101 Gambardella, Matthew XML Developer&#8217;s Guide\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Computer\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 44.95 2000-10-01\u00a0\u00a0 An in-depth look &#8230;<\/p>\n<p>bk102 Ralls, Kim\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Midnight Rain\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Fantasy\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 5.95\u00a0 2000-12-16\u00a0\u00a0 A former architec&#8230;<\/p>\n<p>bk103 Corets, Eva\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Maeve Ascendant\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Fantasy\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 5.95\u00a0 2000-11-17\u00a0\u00a0 After the collaps&#8230;<\/p>\n<p>bk104 Corets, Eva\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Oberon&#8217;s Legacy\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Fantasy\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 5.95\u00a0 2001-03-10\u00a0\u00a0 In post-apocalyps&#8230;<\/p>\n<p>bk105 Corets, Eva\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 The Sundered Grail\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Fantasy\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 5.95\u00a0 2001-09-10\u00a0\u00a0 The two daughters&#8230;<\/p>\n<p>bk106 Randall, Cynthia\u00a0\u00a0\u00a0\u00a0 Lover Birds\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Romance\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 4.95\u00a0 2000-09-02\u00a0\u00a0 When Carla meets &#8230;<\/p>\n<p>bk107 Thurman, Paula\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Splish Splash\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Romance\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 4.95\u00a0 2000-11-02\u00a0\u00a0 A deep sea diver &#8230;<\/p>\n<p>bk108 Knorr, Stefan\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Creepy Crawlies\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Horror\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 4.95\u00a0 2000-12-06\u00a0\u00a0 An anthology of h&#8230;<\/p>\n<p>bk109 Kress, Peter\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Paradox Lost\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Science Fiction 6.95\u00a0 2000-11-02\u00a0\u00a0 After an inadvert&#8230;<\/p>\n<p>bk110 O&#8217;Brien, Tim\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Microsoft .NET: The Prog&#8230; Computer\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 36.95 2000-12-09\u00a0\u00a0 Microsoft&#8217;s .NET &#8230;<\/p>\n<p>bk111 O&#8217;Brien, Tim\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 MSXML3: A Comprehensive &#8230; Computer\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 36.95 2000-12-01\u00a0\u00a0 The Microsoft MSX&#8230;<\/p>\n<p>bk112 Galos, Mike\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Visual Studio 7: A Compr&#8230; Computer\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 49.95 2001-04-16\u00a0\u00a0 Microsoft Visual &#8230;<\/p>\n<p>&nbsp;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>$xdoc.catalog.book[2]<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>id\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : bk103<\/p>\n<p>author\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : Corets, Eva<\/p>\n<p>title\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : Maeve Ascendant<\/p>\n<p>genre\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : Fantasy<\/p>\n<p>price\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : 5.95<\/p>\n<p>publish_date : 2000-11-17<\/p>\n<p>description\u00a0 : After the collapse of a nanotechnology<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 society in England, the young survivors lay the<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 foundation for a new society<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>$xdoc.catalog.book[5].author<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>Randall, Cynthia<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>$xdoc.catalog.book[5].id<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>bk106<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u00a0Notice that all XML nodes in the document are converted to standard PowerShell properties, whether a node has children (e.g. <b>catalog<\/b>) or is a leaf node (e.g. <b>price<\/b>), or whether a leaf node is an element (e.g. <b>author<\/b>) or an attribute (e.g. <b>id<\/b>). In particular (as the last two examples above illustrate), element values and attribute values are treated exactly the same with standard &#8220;dot&#8221; notation.<\/p>\n<h3 id=\"fourth\">Comparison of XPath and Object Approaches<\/h3>\n<p>Which approach is better to access XML data? Table 1 helps you answer this question. The object approach is usually more concise (e.g. line 3), but not always (line 4). XPath, however, is more expressive, in that it allows you to specify some selectors that are not possible with object notation (line 7). However, PowerShell&#8217;s own capabilities can easily fill this gap when using object notation (line 8).<\/p>\n<table class=\"MsoTableMediumShading1Accent3\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p><b>#<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p><b>Select what&#8230;<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p><b>XPath<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p><b>Object<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><b>1<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Entire catalog<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.SelectSingleNode(&#8220;\/catalog&#8221;)<\/p>\n<p>&#8212; or &#8212;<\/p>\n<p>\u00a0($xdoc | <b> Select-Xml<\/b> &#8220;\/catalog&#8221;).Node<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.catalog<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><b>2<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Book collection<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.SelectNodes(&#8220;\/\/book&#8221;)<\/p>\n<p>&#8212; or &#8212;<\/p>\n<p>($xdoc | <b> Select-Xml<\/b> &#8220;\/\/book&#8221;) | <b>%<\/b> { $_.Node }<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.catalog.book<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><b>3<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p>3rd book<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.SelectNodes(&#8220;\/\/book&#8221;).Item(2)<\/p>\n<p>&#8212; or &#8212;<\/p>\n<p>$xdoc.SelectSingleNode(&#8220;\/\/book[3]&#8221;)<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.catalog.book[2]<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><b>4<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Last book<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.SelectSingleNode(&#8220;\/\/book[last()]&#8221;)<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.catalog.book[<\/p>\n<p>\u00a0\u00a0\u00a0 $xdoc.catalog.book.Length-1]<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><b>5<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Author of<br \/>\n 6th book<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.SelectSingleNode(&#8220;\/\/book[6]\/author&#8221;)<\/p>\n<p>\u00a0\u00a0\u00a0 .InnerText<\/p>\n<p>&#8212; or &#8212;<\/p>\n<p>$xdoc.SelectSingleNode(&#8220;(\/\/author)[6]&#8221;)<\/p>\n<p>\u00a0\u00a0\u00a0 .InnerText<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.catalog.book[5].author<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><b>6<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Id of<br \/>\n 6th book<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.SelectSingleNode(&#8220;\/\/book[6]\/@id&#8221;).Value<\/p>\n<p>&#8212; or &#8212;<\/p>\n<p>$xdoc.SelectSingleNode(&#8220;\/\/book[6]&#8221;)<\/p>\n<p>\u00a0\u00a0\u00a0 .GetAttribute(&#8220;id&#8221;)<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.catalog.book[5].id<\/p>\n<p>&#8212; or &#8212;<\/p>\n<p>$xdoc.catalog.book[5].GetAttribute(&#8220;id&#8221;)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><b>7<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Price of book following book written by Kress<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.SelectSingleNode(<\/p>\n<p>\u00a0\u00a0\u00a0 &#8220;\/\/book[contains(author, &#8216;Kress&#8217;)]\/<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 following-sibling::book\/price&#8221;)<\/p>\n<p>&#8212; or &#8212;<\/p>\n<p>$xdoc.SelectSingleNode(<\/p>\n<p>\u00a0\u00a0\u00a0 &#8220;\/\/book[preceding-sibling::book[<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 contains(author, &#8216;Kress&#8217;)]]\/price&#8221;)<\/p>\n<\/td>\n<td valign=\"top\">\n<p>NA<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><b>8<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Books over $40<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.SelectNodes(&#8220;\/\/book[price &gt; 40]&#8221;)<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.catalog.book |<\/p>\n<p>\u00a0\u00a0\u00a0 ? { [decimal]$_.price -gt 40 }<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><b>9<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Unique authors<\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc | <b> Select-Xml<\/b> &#8220;\/\/author&#8221; |<\/p>\n<p>\u00a0\u00a0\u00a0 <b> %<\/b> { $_.Node.InnerText } |<\/p>\n<p>\u00a0\u00a0\u00a0 <b> select<\/b> <i>-Unique<\/i><\/p>\n<\/td>\n<td valign=\"top\">\n<p>$xdoc.catalog.book |<br \/>\n \u00a0\u00a0\u00a0 <b> %<\/b> { $_.author } |<\/p>\n<p>\u00a0\u00a0\u00a0 <b> select<\/b> <i>-Unique<\/i><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"caption\">Table 1 Comparing XPath and object selector approaches for XML access.<\/p>\n<h2 id=\"fifth\">\u00a0Modifying or Creating XML Data<\/h2>\n<p>Given an appreciation of XML selectors from the previous sections, modifying an XML document is quite straightforward because XML selectors (either XPath or object) are <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bkbs2cds.aspx\">L-values<\/a>, i.e. you can write to them as well as read from them! Thus either of these will modify the author of the 6th book:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">$xdoc.SelectSingleNode(\"\/\/book[6]\/author\").InnerText = 'jones'\r\n$xdoc.catalog.book[5].author = 'smith'\u00a0\r\n<\/pre>\n<p>Quite often, \u00a0you might \u00a0have an existing XML file where you want to change one or node values. You&#8217;d probably want to read the file, modify the data, and save the file back to the same name. You have seen the first two steps; the third step is done with the <b>Save<\/b> method on the <b>XmlDocument<\/b>. Putting these all together, then, yields this basic code:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">[xml] $xdoc = get-content \".\\sample-new.xml\"\r\n$xdoc.catalog.book[5].author = 'audubon, j.'\r\n$xdoc.catalog.book[5].title = 'The Birds of America'\r\n$xdoc.Save(\".\\sample-new.xml\")\u00a0\r\n<\/pre>\n<p>That code runs fine-except most of the time it will appear to have failed! This simple bit of code illustrates a seemingly minor but important PowerShell notion; ignorance of this has led to many blog posts claiming it is a bug in PowerShell. The problem\u00a0 is that your working directory and your PowerShell location are <i>not<\/i> the same thing. The above code reads the file just fine, it modifies the data just fine, but it does not necessarily save the new file where you expect it to. <b>Get-Content<\/b>, being a PowerShell cmdlet, sees a file path relative to the PowerShell location. The <b>XmlDocument.Save<\/b> method, on the other hand, sees a file path relative to the PowerShell process&#8217; working directory because that method call is outside of PowerShell. If you have not executed <b>Set-Location<\/b> (or its alias <b>cd<\/b>) in your current PowerShell session, both point to the same directory. To confirm this, execute these two statements:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-Location\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 # displays PowerShell location\r\n[Environment]::CurrentDirectory\u00a0 # displays working directory\r\n<\/pre>\n<p>The safest approach, then, is to use absolute paths to avoid this issue altogether. See Alex Angelopoulos&#8217; article <a href=\"http:\/\/www.itprotoday.com\/management-mobility\/why-powershell-working-directory-and-powershell-location-arent-one-same\"> Why the PowerShell Working Directory and the PowerShell Location Aren&#8217;t One in the Same<\/a> for more.<\/p>\n<h3 id=\"sixth\">Adding XML Data<\/h3>\n<p>Adding new nodes to your XML document takes just a bit more work than modifying the value of an existing node. One approach I like is from Tobias Weltner&#8217;s blog entry <a href=\"http:\/\/powershell.com\/cs\/blogs\/tobias\/archive\/2009\/02\/02\/xml-part-2-write-add-and-change-xml-data.aspx\">Write, Add and Change XML Data<\/a>: take an existing node of the type that you wish to create, make a copy of that node and modify the copy with your new data, and finally insert the copied node into your XML as a sibling of the original. Applying that to our book catalog example, this bit of code creates a new book node and adds it to the end of the collection:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">$book = $xdoc.catalog.book[0].Clone()\r\n$book.author = 'Dickens, Charles'\r\n$book.title = 'The Old Curiousity Shop'\r\n# etc. with remaining properties. . . \r\n[Void] $xdoc.catalog.AppendChild($book)\r\n<\/pre>\n<p>If you wish to add the new book at a different location, say after the 3rd book, use <b>InsertAfter<\/b> instead of <b>AppendChild<\/b>:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">[Void]$xdoc.catalog.InsertAfter($book,$xdoc.catalog.book[2])<\/pre>\n<p>\u00a0(The name of the method <b>InsertAfter<\/b> belies the fact that it does not just <i>add<\/i> nodes; it can <i>move<\/i> nodes, too! The method checks to see whether the node you are asking to add is already in the document. If so, it moves it to the new location you specify. Thus, when you do want to copy nodes, you must start with the <b>Clone<\/b> method as illustrated above.)<\/p>\n<p>For further exploration on manipulating XML data with .NET methods, see <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/t058x2df.aspx\">Process XML Data Using the DOM Model<\/a> on MSDN.<\/p>\n<h3 id=\"seventh\">Using XML for Object Serialization<\/h3>\n<p>PowerShell provides an easy way to persist objects by using <a href=\"http:\/\/technet.microsoft.com\/library\/hh849916.aspx\">Export-Clixml<\/a> to serialize any object and store it in an XML file and <a href=\"http:\/\/technet.microsoft.com\/en-us\/library\/hh849906.aspx\">Import-Clixml<\/a> to restore the object from XML. With XML, unlike most other serialization techniques, \u00a0object integrity is preserved: upon restoring an object from XML all properties are properly typed as is the parent object itself, so all methods on the original object are available on the regenerated object as well. To use <b>Export-Clixml<\/b>, simply pipe any object collection to it and specify a destination file. Here is a simple example showing that the output from <b>Get-ChildItem<\/b>, a collection of <b>FileSystemInfo<\/b> objects, is regenerated:<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p><b> Get-ChildItem<\/b> c:\\usr\\tmp | <b> Export-Clixml<\/b> c:\\usr\\tmp\\files.xml<\/p>\n<p>$fileListing = <b> Import-Clixml<\/b> c:\\usr\\tmp\\files.xml<\/p>\n<p><b> Write-Output<\/b> $fileListing<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p>Mode\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 LastWriteTime\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Length Name<\/p>\n<p>&#8212;-\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8212;&#8212;&#8212;&#8212;-\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8212;&#8212; &#8212;-<\/p>\n<p>d&#8212;-\u00a0\u00a0\u00a0\u00a0 10\/2\/2012\u00a0 6:25 PM\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;DIR&gt; fitnesse<\/p>\n<p>d&#8212;-\u00a0\u00a0\u00a0 11\/23\/2010\u00a0 8:15 AM\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;DIR&gt; Sandcastle<\/p>\n<p>d&#8212;-\u00a0\u00a0\u00a0 11\/16\/2011 10:07 PM\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;DIR&gt; SvnSandbox<\/p>\n<p>-a&#8212;\u00a0\u00a0\u00a0\u00a0 10\/7\/2012\u00a0 7:36 PM\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 152066 filelist.xml<\/p>\n<p>-a&#8212;\u00a0\u00a0\u00a0\u00a0 10\/8\/2012\u00a0 3:27 PM\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 86772 files.xml<\/p>\n<p>-a&#8212;\u00a0\u00a0\u00a0\u00a0 10\/8\/2012\u00a0 1:57 PM\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 4349 sample-new.xml<\/p>\n<p>-a&#8212;\u00a0\u00a0\u00a0\u00a0 10\/6\/2012\u00a0 3:42 PM\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 4550 sample.xml<\/p>\n<p>&nbsp;<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>To master PowerShell, you must know how to use XML. XML is an essential data interchange format because it remains the most reliable way of ensuring that an object&#8217;s data is preserved. Fortunately, PowerShell makes it all easy, as Michael Sorens demonstrates.&hellip;<\/p>\n","protected":false},"author":221868,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[35],"tags":[95506,4242,4635,4871,4217],"coauthors":[6802],"class_list":["post-1740","post","type-post","status-publish","format-standard","hentry","category-powershell","tag-automate","tag-basics","tag-powershell","tag-sysadmin","tag-xml"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1740","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221868"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1740"}],"version-history":[{"count":7,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1740\/revisions"}],"predecessor-version":[{"id":75868,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1740\/revisions\/75868"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1740"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1740"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1740"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1740"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}