PoshCode Logo PowerShell Code Repository

New-XML 2 by Joel Bennett 30 months ago (modification of post by Joel Bennett view diff)
diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/1244"></script>download | new post

An update to my mini-DSL for generating XML documents.

Note that I used System.Linq.XML (and output an XDocument) instead of the old XmlDocument… This means you have to have .Net 3.5 (LINQ) installed. It also means that if you want to be able to use the output via PowerShell’s magic XML dot-notation, you have to cast it to XmlDocument, just write: [xml]$xml = New-XML ... or you can cast it to string, or whatever.

  1. #requires -version 2.0
  2. #### NOTE: you can revert this to work in PowerShell 1.0 by just removing the [Parameter(...)] lines
  3. ####       BUT YOU WILL HAVE TO pass the $Version $Encoding $Standalone parameters EACH TIME
  4. ####       UNLESS you remove them, and switch back to a hardcoded XDeclaration ... or something.
  5. ####################################################################################################
  6. #### I still have to add documentation comments to these, but in the meantime ...
  7. ### please see the samples at the bottom to understand how to use them :)
  8. ####
  9. $xlr8r = [type]::gettype("System.Management.Automation.TypeAccelerators")
  10. $xlinq = [Reflection.Assembly]::Load("System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
  11. $xlinq.GetTypes() | ? { $_.IsPublic -and !$_.IsSerializable -and $_.Name -ne "Extensions" -and !$xlr8r::Get[$_.Name] } | % {
  12.   $xlr8r::Add( $_.Name, $_.FullName )
  13. }
  14.  
  15. function New-Xml {
  16. Param(
  17.    [Parameter(Mandatory = $true, Position = 0)]
  18.    [System.Xml.Linq.XName]$root
  19. ,
  20.    [Parameter(Mandatory = $false)]
  21.    [string]$Version = "1.0"
  22. ,
  23.    [Parameter(Mandatory = $false)]
  24.    [string]$Encoding = "UTF-8"
  25. ,
  26.    [Parameter(Mandatory = $false)]
  27.    [string]$Standalone = "yes"
  28. ,
  29.    [Parameter(Position=99, Mandatory = $false, ValueFromRemainingArguments=$true)]
  30.    [PSObject[]]$args
  31. )
  32. BEGIN {
  33.    if(![string]::IsNullOrEmpty( $root.NamespaceName )) {
  34.       Function New-XmlDefaultElement {
  35.          Param([System.Xml.Linq.XName]$tag)
  36.          if([string]::IsNullOrEmpty( $tag.NamespaceName )) {
  37.             $tag = $($root.Namespace) + $tag
  38.          }
  39.          New-XmlElement $tag @args
  40.       }
  41.       Set-Alias xe New-XmlDefaultElement
  42.    }
  43. }
  44. PROCESS {
  45.    #New-Object XDocument (New-Object XDeclaration "1.0", "UTF-8", "yes"),(
  46.    New-Object XDocument (New-Object XDeclaration $Version, $Encoding, $standalone),(
  47.       New-Object XElement $(
  48.          $root
  49.          #  foreach($ns in $namespace){
  50.             #  $name,$url = $ns -split ":",2
  51.             #  New-Object XAttribute ([XNamespace]::Xmlns + $name),$url
  52.          #  }
  53.          while($args) {
  54.             $attrib, $value, $args = $args
  55.             if($attrib -is [ScriptBlock]) {
  56.                &$attrib
  57.             } elseif ( $value -is [ScriptBlock] -and "-Content".StartsWith($attrib)) {
  58.                &$value
  59.             } elseif ( $value -is [XNamespace]) {
  60.                New-XmlAttribute ([XNamespace]::Xmlns + $attrib.TrimStart("-")) $value
  61.             } else {
  62.                New-XmlAttribute $attrib.TrimStart("-") $value
  63.             }
  64.          }
  65.       ))
  66. }
  67. END {
  68.    Set-Alias xe New-XmlElement
  69. }
  70. }
  71. function New-XmlAttribute {
  72. Param($name,$value)
  73.    New-Object XAttribute $name,$value
  74. }
  75. Set-Alias xa New-XmlAttribute
  76.  
  77.  
  78. function New-XmlElement {
  79.   Param([System.Xml.Linq.XName]$tag)
  80.   Write-Verbose $($args | %{ $_ | Out-String } | Out-String)
  81.   New-Object XElement $(
  82.      $tag
  83.      while($args) {
  84.         $attrib, $value, $args = $args
  85.         if($attrib -is [ScriptBlock]) {
  86.            &$attrib
  87.         } elseif ( $value -is [ScriptBlock] -and "-Content".StartsWith($attrib)) {
  88.            &$value
  89.         } elseif ( $value -is [XNamespace]) {
  90.             New-Object XAttribute ([XNamespace]::Xmlns + $attrib.TrimStart("-")),$value
  91.         } else {
  92.            New-Object XAttribute $attrib.TrimStart("-"), $value
  93.         }
  94.      }
  95.    )
  96. }
  97. Set-Alias xe New-XmlElement
  98.  
  99.  
  100.  
  101.  
  102. ####################################################################################################
  103. ###### EXAMPLE SCRIPT: NOTE the `: in the http`: is only there for PoshCode, you can just use http:
  104. # [XNamespace]$dc = "http`://purl.org/dc/elements/1.1"
  105. #
  106. # $xml = New-Xml rss -dc $dc -version "2.0" {
  107. #    xe channel {
  108. #       xe title {"Test RSS Feed"}
  109. #       xe link {"http`://HuddledMasses.org"}
  110. #       xe description {"An RSS Feed generated simply to demonstrate my XML DSL"}
  111. #       xe ($dc + "language") {"en"}
  112. #       xe ($dc + "creator") {"Jaykul@HuddledMasses.org"}
  113. #       xe ($dc + "rights") {"Copyright 2009, CC-BY"}
  114. #       xe ($dc + "date") {(Get-Date -f u) -replace " ","T"}
  115. #       xe item {
  116. #          xe title {"The First Item"}
  117. #          xe link {"http`://huddledmasses.org/new-site-new-layout-lost-posts/"}
  118. #          xe guid -isPermaLink true {"http`://huddledmasses.org/new-site-new-layout-lost-posts/"}
  119. #          xe description {"Ema Lazarus' Poem"}
  120. #          xe pubDate  {(Get-Date 10/31/2003 -f u) -replace " ","T"}
  121. #       }
  122. #    }
  123. # }
  124. #
  125. # $xml.Declaration.ToString()  ## I can't find a way to have this included in the $xml.ToString()
  126. # $xml.ToString()
  127. #
  128. ####### OUTPUT: (NOTE: I added the space in the http: to paste it on PoshCode -- those aren't in the output)
  129. # <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  130. # <rss xmlns:dc="http ://purl.org/dc/elements/1.1" version="2.0">
  131. #   <channel>
  132. #     <title>Test RSS Feed</title>
  133. #     <link>http ://HuddledMasses.org</link>
  134. #     <description>An RSS Feed generated simply to demonstrate my XML DSL</description>
  135. #     <dc:language>en</dc:language>
  136. #     <dc:creator>Jaykul@HuddledMasses.org</dc:creator>
  137. #     <dc:rights>Copyright 2009, CC-BY</dc:rights>
  138. #     <dc:date>2009-07-26T00:50:08Z</dc:date>
  139. #     <item>
  140. #       <title>The First Item</title>
  141. #       <link>http ://huddledmasses.org/new-site-new-layout-lost-posts/</link>
  142. #       <guid isPermaLink="true">http ://huddledmasses.org/new-site-new-layout-lost-posts/</guid>
  143. #       <description>Ema Lazarus' Poem</description>
  144. #       <pubDate>2003-10-31T00:00:00Z</pubDate>
  145. #     </item>
  146. #   </channel>
  147. # </rss>
  148.  
  149.  
  150. ####################################################################################################
  151. ###### ANOTHER EXAMPLE SCRIPT, this time with a default namespace
  152. ## IMPORTANT! ## NOTE that I use the "xe" shortcut which is redefined when you specify a namespace
  153. ##            ## for the root element, so that all child elements (by default) inherit that.
  154. ##            ## You can still control the prefixes by passing the namespace as a parameter
  155. ##            ## e.g.: -atom $atom
  156. ###### The `: in the http`: is still only there for PoshCode, you can just use http: ...
  157. ####################################################################################################
  158. #
  159. #   [XNamespace]$atom="http`://www.w3.org/2005/Atom"
  160. #   [XNamespace]$dc = "http`://purl.org/dc/elements/1.1"
  161. #  
  162. #   New-Xml ($atom + "feed") -Encoding "UTF-16" -$([XNamespace]::Xml +'lang') "en-US" -dc $dc {
  163. #      xe title {"Test First Entry"}
  164. #      xe link {"http`://HuddledMasses.org"}
  165. #      xe updated {(Get-Date -f u) -replace " ","T"}
  166. #      xe author {
  167. #         xe name {"Joel Bennett"}
  168. #         xe uri {"http`://HuddledMasses.org"}
  169. #      }
  170. #      xe id {"http`://huddledmasses.org/" }
  171. #
  172. #      xe entry {
  173. #         xe title {"Test First Entry"}
  174. #         xe link {"http`://HuddledMasses.org/new-site-new-layout-lost-posts/" }
  175. #         xe id {"http`://huddledmasses.org/new-site-new-layout-lost-posts/" }
  176. #         xe updated {(Get-Date 10/31/2003 -f u) -replace " ","T"}
  177. #         xe summary {"Ema Lazarus' Poem"}
  178. #         xe link -rel license -href "http://creativecommons.org/licenses/by/3.0/" -title "CC By-Attribution"
  179. #         xe ($dc + "rights") {"Copyright 2009, Some rights reserved (licensed under the Creative Commons Attribution 3.0 Unported license)"}
  180. #         xe category -scheme "http://huddledmasses.org/tag/" -term "huddled-masses"
  181. #      }
  182. #   } | % { $_.Declaration.ToString(); $_.ToString() }
  183. #
  184. ####### OUTPUT: (NOTE: I added the spaces again to the http: to paste it on PoshCode)
  185. # <?xml version="1.0" encoding="UTF-16" standalone="yes"?>
  186. # <feed xml:lang="en-US" xmlns="http ://www.w3.org/2005/Atom">
  187. #   <title>Test First Entry</title>
  188. #   <link>http ://HuddledMasses.org</link>
  189. #   <updated>2009-07-29T17:25:49Z</updated>
  190. #   <author>
  191. #      <name>Joel Bennett</name>
  192. #      <uri>http ://HuddledMasses.org</uri>
  193. #   </author>
  194. #   <id>http ://huddledmasses.org/</id>
  195. #   <entry>
  196. #     <title>Test First Entry</title>
  197. #     <link>http ://HuddledMasses.org/new-site-new-layout-lost-posts/</link>
  198. #     <id>http ://huddledmasses.org/new-site-new-layout-lost-posts/</id>
  199. #     <updated>2003-10-31T00:00:00Z</updated>
  200. #     <summary>Ema Lazarus' Poem</summary>
  201. #     <link rel="license" href="http ://creativecommons.org/licenses/by/3.0/" title="CC By-Attribution" />
  202. #     <dc:rights>Copyright 2009, Some rights reserved (licensed under the Creative Commons Attribution 3.0 Unported license)</dc:rights>
  203. #     <category scheme="http ://huddledmasses.org/tag/" term="huddled-masses" />
  204. #   </entry>
  205. # </feed>
  206. #
  207. #

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me