PoshCode Logo PowerShell Code Repository

Xml Module 3.1 by Joel Bennett 23 months ago (modification of post by Joel Bennett view diff)
View followups from Joel Bennett | diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/1676"></script>download | new post

Improves over the built-in Select-XML by leveraging Remove-XmlNamespace to provide a -RemoveNamespace parameter — if it’s supplied, all of the namespace declarations and prefixes are removed from all XML nodes (by an XSL transform) before searching. Note that this means that the returned results will not have namespaces in them, even if the input XML did.

Also, only raw XmlNodes are returned from this function, so the output isn’t currently compatible with the built in Select-Xml, but is equivalent to using Select-Xml … | Select-Object -Expand Node

This version is a bug-fix for the previous release (oops).

  1. #requires -version 2.0
  2.  
  3. # Improves over the built-in Select-XML by leveraging Remove-XmlNamespace http://poshcode.org/1492
  4. # to provide a -RemoveNamespace parameter -- if it's supplied, all of the namespace declarations
  5. # and prefixes are removed from all XML nodes (by an XSL transform) before searching.
  6. # IMPORTANT: returned results *will not* have namespaces in them, even if the input XML did.
  7.  
  8. # Also, only raw XmlNodes are returned from this function, so the output isn't completely compatible
  9. # with the built in Select-Xml. It's equivalent to using Select-Xml ... | Select-Object -Expand Node
  10.  
  11. # Version History:
  12. # Select-Xml 2.0 This was the first script version I wrote.
  13. #                it didn't function identically to the built-in Select-Xml with regards to parameter parsing
  14. # Select-Xml 2.1 Matched the built-in Select-Xml parameter sets, it's now a drop-in replacement
  15. #                BUT only if you were using the original with: Select-Xml ... | Select-Object -Expand Node
  16. # Select-Xml 2.2 Fixes a bug in the -Content parameterset where -RemoveNamespace was *presumed*
  17. # Version    3.0 Added New-Xml and associated generation functions for my XML DSL
  18. # Version    3.1 Fixed a really ugly bug in New-Xml in 3.0 which I should not have released
  19.  
  20. $xlr8r = [type]::gettype("System.Management.Automation.TypeAccelerators")
  21. $xlinq = [Reflection.Assembly]::Load("System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
  22. $xlinq.GetTypes() | ? { $_.IsPublic -and !$_.IsSerializable -and $_.Name -ne "Extensions" -and !$xlr8r::Get[$_.Name] } | % {
  23.   $xlr8r::Add( $_.Name, $_.FullName )
  24. }
  25. if(!$xlr8r::Get["Stack"]) {
  26.    $xlr8r::Add( "Stack", "System.Collections.Generic.Stack``1, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" )
  27. }
  28.  
  29. function Format-XML {
  30. #.Synopsis
  31. #   Pretty-print formatted XML source
  32. #.Description
  33. #       Runs an XmlDocument through an auto-indenting XmlWriter
  34. #.Parameter Xml
  35. #       The Xml Document
  36. #.Parameter Indent
  37. #       The indent level (defaults to 2 spaces)
  38. Param(
  39.         [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
  40.         [xml]$xml
  41. ,
  42.         [Parameter(Mandatory=$false)]
  43.         $indent=2
  44. )
  45.     $StringWriter = New-Object System.IO.StringWriter
  46.     $XmlWriter = New-Object System.XMl.XmlTextWriter $StringWriter
  47.     $xmlWriter.Formatting = "indented"
  48.     $xmlWriter.Indentation = $Indent
  49.     $xml.WriteContentTo($XmlWriter)
  50.     $XmlWriter.Flush()
  51.     $StringWriter.Flush()
  52.     Write-Output $StringWriter.ToString()
  53. }
  54. Set-Alias fxml Format-Xml
  55.  
  56. function Select-Xml {
  57. #.Synopsis
  58. #  The Select-XML cmdlet lets you use XPath queries to search for text in XML strings and documents. Enter an XPath query, and use the Content, Path, or Xml parameter to specify the XML to be searched.
  59. #.Description
  60. #  Improves over the built-in Select-XML by leveraging Remove-XmlNamespace to provide a -RemoveNamespace parameter -- if it's supplied, all of the namespace declarations and prefixes are removed from all XML nodes (by an XSL transform) before searching.  
  61. #  
  62. #  However, only raw XmlNodes are returned from this function, so the output isn't currently compatible with the built in Select-Xml, but is equivalent to using Select-Xml ... | Select-Object -Expand Node
  63. #
  64. #  Also note that if the -RemoveNamespace switch is supplied the returned results *will not* have namespaces in them, even if the input XML did, and entities get expanded automatically.
  65. #.Parameter Content
  66. #  Specifies a string that contains the XML to search. You can also pipe strings to Select-XML.
  67. #.Parameter Namespace
  68. #   Specifies a hash table of the namespaces used in the XML. Use the format @{<namespaceName> = <namespaceUri>}.
  69. #.Parameter Path
  70. #   Specifies the path and file names of the XML files to search.  Wildcards are permitted.
  71. #.Parameter Xml
  72. #  Specifies one or more XML nodes to search.
  73. #.Parameter XPath
  74. #  Specifies an XPath search query. The query language is case-sensitive. This parameter is required.
  75. #.Parameter RemoveNamespace
  76. #  Allows the execution of XPath queries without namespace qualifiers.
  77. #  
  78. #  If you specify the -RemoveNamespace switch, all namespace declarations and prefixes are actually removed from the Xml before the XPath search query is evaluated, and your XPath query should therefore NOT contain any namespace prefixes.
  79. #
  80. #  Note that this means that the returned results *will not* have namespaces in them, even if the input XML did, and entities get expanded automatically.
  81. [CmdletBinding(DefaultParameterSetName="Xml")]
  82. PARAM(
  83.    [Parameter(Position=1,ParameterSetName="Path",Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
  84.    [ValidateNotNullOrEmpty()]
  85.    [Alias("PSPath")]
  86.    [String[]]$Path
  87. ,
  88.    [Parameter(Position=1,ParameterSetName="Xml",Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  89.    [ValidateNotNullOrEmpty()]
  90.    [Alias("Node")]
  91.    [System.Xml.XmlNode[]]$Xml
  92. ,
  93.    [Parameter(ParameterSetName="Content",Mandatory=$true,ValueFromPipeline=$true)]
  94.    [ValidateNotNullOrEmpty()]
  95.    [String[]]$Content
  96. ,
  97.    [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]
  98.    [ValidateNotNullOrEmpty()]
  99.    [Alias("Query")]
  100.    [String[]]$XPath
  101. ,
  102.    [Parameter(Mandatory=$false)]
  103.    [ValidateNotNullOrEmpty()]
  104.    [Hashtable]$Namespace
  105. ,
  106.    [Switch]$RemoveNamespace
  107. )
  108. BEGIN {
  109.    function Select-Node {
  110.    PARAM([Xml.XmlNode]$Xml, [String[]]$XPath, $NamespaceManager)
  111.    BEGIN {
  112.       foreach($node in $xml) {
  113.          if($NamespaceManager -is [Hashtable]) {
  114.             $nsManager = new-object System.Xml.XmlNamespaceManager $node.NameTable
  115.             foreach($ns in $Namespace.GetEnumerator()) {
  116.                $nsManager.AddNamespace( $ns.Key, $ns.Value )
  117.             }
  118.          }
  119.          
  120.          foreach($path in $xpath) {
  121.             $node.SelectNodes($path, $NamespaceManager)
  122.    }  }  }  }
  123.  
  124.    [Text.StringBuilder]$XmlContent = [String]::Empty
  125. }
  126.  
  127. PROCESS {
  128.    $NSM = $Null; if($PSBoundParameters.ContainsKey("Namespace")) { $NSM = $Namespace }
  129.  
  130.    switch($PSCmdlet.ParameterSetName) {
  131.       "Content" {
  132.          $null = $XmlContent.AppendLine( $Content -Join "`n" )
  133.       }
  134.       "Path" {
  135.          foreach($file in Get-ChildItem $Path) {
  136.             [Xml]$Xml = Get-Content $file
  137.             if($RemoveNamespace) {
  138.                $Xml = Remove-XmlNamespace $Xml
  139.             }
  140.             Select-Node $Xml $XPath  $NSM
  141.          }
  142.       }
  143.       "Xml" {
  144.          foreach($node in $Xml) {
  145.             if($RemoveNamespace) {
  146.                $node = Remove-XmlNamespace $node
  147.             }
  148.             Select-Node $node $XPath $NSM
  149.          }
  150.       }
  151.    }
  152. }
  153. END {
  154.    if($PSCmdlet.ParameterSetName -eq "Content") {
  155.       [Xml]$Xml = $XmlContent.ToString()
  156.       if($RemoveNamespace) {
  157.          $Xml = Remove-XmlNamespace $Xml
  158.       }
  159.       Select-Node $Xml $XPath  $NSM
  160.    }
  161. }
  162.  
  163. }
  164. Set-Alias slxml Select-Xml
  165.  
  166. function Convert-Node {
  167. #.Synopsis
  168. # Convert a single XML Node via XSL stylesheets
  169. param(
  170. [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
  171. [System.Xml.XmlReader]$XmlReader,
  172. [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$false)]
  173. [System.Xml.Xsl.XslCompiledTransform]$StyleSheet
  174. )
  175. PROCESS {
  176.    $output = New-Object IO.StringWriter
  177.    $StyleSheet.Transform( $XmlReader, $null, $output )
  178.    Write-Output $output.ToString()
  179. }
  180. }
  181.    
  182. function Convert-Xml {
  183. #.Synopsis
  184. #  The Convert-XML function lets you use Xslt to transform XML strings and documents.
  185. #.Description
  186. #.Parameter Content
  187. #  Specifies a string that contains the XML to search. You can also pipe strings to Select-XML.
  188. #.Parameter Namespace
  189. #   Specifies a hash table of the namespaces used in the XML. Use the format @{<namespaceName> = <namespaceUri>}.
  190. #.Parameter Path
  191. #   Specifies the path and file names of the XML files to search.  Wildcards are permitted.
  192. #.Parameter Xml
  193. #  Specifies one or more XML nodes to search.
  194. #.Parameter Xsl
  195. #  Specifies an Xml StyleSheet to transform with...
  196. [CmdletBinding(DefaultParameterSetName="Xml")]
  197. PARAM(
  198.    [Parameter(Position=1,ParameterSetName="Path",Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
  199.    [ValidateNotNullOrEmpty()]
  200.    [Alias("PSPath")]
  201.    [String[]]$Path
  202. ,
  203.    [Parameter(Position=1,ParameterSetName="Xml",Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  204.    [ValidateNotNullOrEmpty()]
  205.    [Alias("Node")]
  206.    [System.Xml.XmlNode[]]$Xml
  207. ,
  208.    [Parameter(ParameterSetName="Content",Mandatory=$true,ValueFromPipeline=$true)]
  209.    [ValidateNotNullOrEmpty()]
  210.    [String[]]$Content
  211. ,
  212.    [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]
  213.    [ValidateNotNullOrEmpty()]
  214.    [Alias("StyleSheet")]
  215.    [String[]]$Xslt
  216. )
  217. BEGIN {
  218.    $StyleSheet = New-Object System.Xml.Xsl.XslCompiledTransform
  219.    if(Test-Path @($Xslt)[0] -EA 0) {
  220.       Write-Verbose "Loading Stylesheet from $(Resolve-Path @($Xslt)[0])"
  221.       $StyleSheet.Load( (Resolve-Path @($Xslt)[0]) )
  222.    } else {
  223.       Write-Verbose "$Xslt"
  224.       $StyleSheet.Load(([System.Xml.XmlReader]::Create((New-Object System.IO.StringReader ($Xslt -join "`n")))))
  225.    }
  226.    [Text.StringBuilder]$XmlContent = [String]::Empty
  227. }
  228. PROCESS {
  229.    switch($PSCmdlet.ParameterSetName) {
  230.       "Content" {
  231.          $null = $XmlContent.AppendLine( $Content -Join "`n" )
  232.       }
  233.       "Path" {
  234.          foreach($file in Get-ChildItem $Path) {
  235.             Convert-Node -Xml ([System.Xml.XmlReader]::Create((Resolve-Path $file))) $StyleSheet
  236.          }
  237.       }
  238.       "Xml" {
  239.          foreach($node in $Xml) {
  240.             Convert-Node -Xml (New-Object Xml.XmlNodeReader $node) $StyleSheet
  241.          }
  242.       }
  243.    }
  244. }
  245. END {
  246.    if($PSCmdlet.ParameterSetName -eq "Content") {
  247.       [Xml]$Xml = $XmlContent.ToString()
  248.       Convert-Node -Xml $Xml $StyleSheet
  249.    }
  250. }
  251. }
  252. Set-Alias cvxml Convert-Xml
  253.  
  254. function Remove-XmlNamespace {
  255. #.Synopsis
  256. #  Removes namespace definitions and prefixes from xml documents
  257. #.Description
  258. #  Runs an xml document through an XSL Transformation to remove namespaces from it if they exist.
  259. #  Entities are also naturally expanded
  260. #.Parameter Content
  261. #  Specifies a string that contains the XML to transform.
  262. #.Parameter Path
  263. #  Specifies the path and file names of the XML files to transform. Wildcards are permitted.
  264. #
  265. #  There will bne one output document for each matching input file.
  266. #.Parameter Xml
  267. #  Specifies one or more XML documents to transform
  268. [CmdletBinding(DefaultParameterSetName="Xml")]
  269. PARAM(
  270.    [Parameter(Position=1,ParameterSetName="Path",Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
  271.    [ValidateNotNullOrEmpty()]
  272.    [Alias("PSPath")]
  273.    [String[]]$Path
  274. ,
  275.    [Parameter(Position=1,ParameterSetName="Xml",Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  276.    [ValidateNotNullOrEmpty()]
  277.    [Alias("Node")]
  278.    [System.Xml.XmlNode[]]$Xml
  279. ,
  280.    [Parameter(ParameterSetName="Content",Mandatory=$true,ValueFromPipeline=$true)]
  281.    [ValidateNotNullOrEmpty()]
  282.    [String[]]$Content
  283. ,
  284.    [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]
  285.    [ValidateNotNullOrEmpty()]
  286.    [Alias("StyleSheet")]
  287.    [String[]]$Xslt
  288. )
  289. BEGIN {
  290.    $StyleSheet = New-Object System.Xml.Xsl.XslCompiledTransform
  291.    $StyleSheet.Load(([System.Xml.XmlReader]::Create((New-Object System.IO.StringReader @"
  292. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  293.   <xsl:output method="xml" indent="yes"/>
  294.   <xsl:template match="/|comment()|processing-instruction()">
  295.      <xsl:copy>
  296.         <xsl:apply-templates/>
  297.      </xsl:copy>
  298.   </xsl:template>
  299.  
  300.   <xsl:template match="*">
  301.      <xsl:element name="{local-name()}">
  302.         <xsl:apply-templates select="@*|node()"/>
  303.      </xsl:element>
  304.   </xsl:template>
  305.  
  306.   <xsl:template match="@*">
  307.      <xsl:attribute name="{local-name()}">
  308.         <xsl:value-of select="."/>
  309.      </xsl:attribute>
  310.   </xsl:template>
  311. </xsl:stylesheet>
  312. "@))))
  313.    [Text.StringBuilder]$XmlContent = [String]::Empty
  314. }
  315. PROCESS {
  316.    switch($PSCmdlet.ParameterSetName) {
  317.       "Content" {
  318.          $null = $XmlContent.AppendLine( $Content -Join "`n" )
  319.       }
  320.       "Path" {
  321.          foreach($file in Get-ChildItem $Path) {
  322.             [Xml]$Xml = Get-Content $file
  323.             Convert-Node -Xml $Xml $StyleSheet
  324.          }
  325.       }
  326.       "Xml" {
  327.          $Xml | Convert-Node $StyleSheet
  328.       }
  329.    }
  330. }
  331. END {
  332.    if($PSCmdlet.ParameterSetName -eq "Content") {
  333.       [Xml]$Xml = $XmlContent.ToString()
  334.       Convert-Node -Xml $Xml $StyleSheet
  335.    }
  336. }
  337. }
  338. Set-Alias rmns Remove-XmlNamespace
  339.  
  340.  
  341.  
  342. function New-XDocument {
  343. #.Synopsis
  344. #       Creates a new XDocument (the new xml document type)
  345. #.Description
  346. #  This is the root for a new XML mini-dsl, akin to New-BootsWindow for XAML
  347. #  It creates a new XDocument, and takes scritpblock(s) to define it's contents
  348. #.Parameter root
  349. #       The root node name
  350. #.Parameter version
  351. #       Optional: the XML version. Defaults to 1.0
  352. #.Parameter encoding
  353. #       Optional: the Encoding. Defaults to UTF-8
  354. #.Parameter standalone
  355. #  Optional: whether to specify standalone in the xml declaration. Defaults to "yes"
  356. #.Parameter args
  357. #       this is where all the dsl magic happens. Please see the Examples. :)
  358. #
  359. #.Example
  360. # [XNamespace]$dc = "http`://purl.org/dc/elements/1.1"
  361. # $xml = New-XDocument rss -dc $dc -version "2.0" {
  362. #    xe channel {
  363. #       xe title {"Test RSS Feed"}
  364. #       xe link {"http`://HuddledMasses.org"}
  365. #       xe description {"An RSS Feed generated simply to demonstrate my XML DSL"}
  366. #       xe ($dc + "language") {"en"}
  367. #       xe ($dc + "creator") {"Jaykul@HuddledMasses.org"}
  368. #       xe ($dc + "rights") {"Copyright 2009, CC-BY"}
  369. #       xe ($dc + "date") {(Get-Date -f u) -replace " ","T"}
  370. #       xe item {
  371. #          xe title {"The First Item"}
  372. #          xe link {"http`://huddledmasses.org/new-site-new-layout-lost-posts/"}
  373. #          xe guid -isPermaLink true {"http`://huddledmasses.org/new-site-new-layout-lost-posts/"}
  374. #          xe description {"Ema Lazarus' Poem"}
  375. #          xe pubDate  {(Get-Date 10/31/2003 -f u) -replace " ","T"}
  376. #       }
  377. #    }
  378. # }
  379. #
  380. # $xml.Declaration.ToString()  ## I can't find a way to have this included in the $xml.ToString()
  381. # $xml.ToString()
  382. #
  383. #
  384. # OUTPUT: (NOTE: I added the space in the http: to paste it on PoshCode -- those aren't in the output)
  385. #
  386. #
  387. # <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  388. # <rss xmlns:dc="http ://purl.org/dc/elements/1.1" version="2.0">
  389. #   <channel>
  390. #     <title>Test RSS Feed</title>
  391. #     <link>http ://HuddledMasses.org</link>
  392. #     <description>An RSS Feed generated simply to demonstrate my XML DSL</description>
  393. #     <dc:language>en</dc:language>
  394. #     <dc:creator>Jaykul@HuddledMasses.org</dc:creator>
  395. #     <dc:rights>Copyright 2009, CC-BY</dc:rights>
  396. #     <dc:date>2009-07-26T00:50:08Z</dc:date>
  397. #     <item>
  398. #       <title>The First Item</title>
  399. #       <link>http ://huddledmasses.org/new-site-new-layout-lost-posts/</link>
  400. #       <guid isPermaLink="true">http ://huddledmasses.org/new-site-new-layout-lost-posts/</guid>
  401. #       <description>Ema Lazarus' Poem</description>
  402. #       <pubDate>2003-10-31T00:00:00Z</pubDate>
  403. #     </item>
  404. #   </channel>
  405. # </rss>
  406. #
  407. #.Example
  408. #  This time with a default namespace
  409. ## IMPORTANT! ## NOTE that I use the "xe" shortcut which is redefined when you specify a namespace
  410. ##            ## for the root element, so that all child elements (by default) inherit that.
  411. ##            ## You can still control the prefixes by passing the namespace as a parameter
  412. ##            ## e.g.: -atom $atom
  413. ## The `: in the http`: is still only there for PoshCode, you can just use http: ...
  414. #
  415. #   [XNamespace]$atom="http`://www.w3.org/2005/Atom"
  416. #   [XNamespace]$dc = "http`://purl.org/dc/elements/1.1"
  417. #  
  418. #   New-Xml ($atom + "feed") -Encoding "UTF-16" -$([XNamespace]::Xml +'lang') "en-US" -dc $dc {
  419. #      xe title {"Test First Entry"}
  420. #      xe link {"http`://HuddledMasses.org"}
  421. #      xe updated {(Get-Date -f u) -replace " ","T"}
  422. #      xe author {
  423. #         xe name {"Joel Bennett"}
  424. #         xe uri {"http`://HuddledMasses.org"}
  425. #      }
  426. #      xe id {"http`://huddledmasses.org/" }
  427. #
  428. #      xe entry {
  429. #         xe title {"Test First Entry"}
  430. #         xe link {"http`://HuddledMasses.org/new-site-new-layout-lost-posts/" }
  431. #         xe id {"http`://huddledmasses.org/new-site-new-layout-lost-posts/" }
  432. #         xe updated {(Get-Date 10/31/2003 -f u) -replace " ","T"}
  433. #         xe summary {"Ema Lazarus' Poem"}
  434. #         xe link -rel license -href "http://creativecommons.org/licenses/by/3.0/" -title "CC By-Attribution"
  435. #         xe ($dc + "rights") {"Copyright 2009, Some rights reserved (licensed under the Creative Commons Attribution 3.0 Unported license)"}
  436. #         xe category -scheme "http://huddledmasses.org/tag/" -term "huddled-masses"
  437. #      }
  438. #   } | % { $_.Declaration.ToString(); $_.ToString() }
  439. #
  440. #
  441. #  OUTPUT: (NOTE: I added the spaces again to the http: to paste it on PoshCode)
  442. #
  443. #
  444. # <?xml version="1.0" encoding="UTF-16" standalone="yes"?>
  445. # <feed xml:lang="en-US" xmlns="http ://www.w3.org/2005/Atom">
  446. #   <title>Test First Entry</title>
  447. #   <link>http ://HuddledMasses.org</link>
  448. #   <updated>2009-07-29T17:25:49Z</updated>
  449. #   <author>
  450. #      <name>Joel Bennett</name>
  451. #      <uri>http ://HuddledMasses.org</uri>
  452. #   </author>
  453. #   <id>http ://huddledmasses.org/</id>
  454. #   <entry>
  455. #     <title>Test First Entry</title>
  456. #     <link>http ://HuddledMasses.org/new-site-new-layout-lost-posts/</link>
  457. #     <id>http ://huddledmasses.org/new-site-new-layout-lost-posts/</id>
  458. #     <updated>2003-10-31T00:00:00Z</updated>
  459. #     <summary>Ema Lazarus' Poem</summary>
  460. #     <link rel="license" href="http ://creativecommons.org/licenses/by/3.0/" title="CC By-Attribution" />
  461. #     <dc:rights>Copyright 2009, Some rights reserved (licensed under the Creative Commons Attribution 3.0 Unported license)</dc:rights>
  462. #     <category scheme="http ://huddledmasses.org/tag/" term="huddled-masses" />
  463. #   </entry>
  464. # </feed>
  465. #
  466. #
  467. Param(
  468.    [Parameter(Mandatory = $true, Position = 0)]
  469.    [System.Xml.Linq.XName]$root
  470. ,
  471.    [Parameter(Mandatory = $false)]
  472.    [string]$Version = "1.0"
  473. ,
  474.    [Parameter(Mandatory = $false)]
  475.    [string]$Encoding = "UTF-8"
  476. ,
  477.    [Parameter(Mandatory = $false)]
  478.    [string]$Standalone = "yes"
  479. ,
  480.    [Parameter(Position=99, Mandatory = $false, ValueFromRemainingArguments=$true)]
  481.    [PSObject[]]$args
  482. )
  483. BEGIN {
  484.    $script:NameSpaceStack = New-Object 'Stack[XNamespace]'
  485.    if(![string]::IsNullOrEmpty( $root.NamespaceName )) {
  486.                 $script:NameSpaceStack.Push( $root.Namespace )
  487.    } elseif( $script:NameSpaceStack.Count -gt 0 ) {
  488.       $script:NameSpaceStack.Push( $script:NameSpaceStack.Peek() )
  489.    } else {
  490.       $script:NameSpaceStack.Push( $null )
  491.         }
  492. }
  493. PROCESS {
  494.    #New-Object XDocument (New-Object XDeclaration "1.0", "UTF-8", "yes"),(
  495.    New-Object XDocument (New-Object XDeclaration $Version, $Encoding, $standalone),(
  496.       New-Object XElement $(
  497.          $root
  498.          while($args) {
  499.             $attrib, $value, $args = $args
  500.             if($attrib -is [ScriptBlock]) {
  501.                &$attrib
  502.             } elseif ( $value -is [ScriptBlock] -and "-Content".StartsWith($attrib)) {
  503.                &$value
  504.             } elseif ( $value -is [XNamespace]) {
  505.                New-XAttribute ([XNamespace]::Xmlns + $attrib.TrimStart("-")) $value
  506.             } else {
  507.                New-XAttribute $attrib.TrimStart("-") $value
  508.             }
  509.          }
  510.       ))
  511. }
  512. END {
  513.    #if(![string]::IsNullOrEmpty( $root.NamespaceName )) {
  514.       $null = $script:NameSpaceStack.Pop()
  515.    #}
  516. }
  517. }
  518.  
  519. Set-Alias xml New-XDocument
  520. Set-Alias New-Xml New-XDocument
  521.  
  522. function New-XAttribute {
  523. #.Synopsys
  524. #       Creates a new XAttribute (an xml attribute on an XElement for XDocument)
  525. #.Description
  526. #  This is the work-horse for the XML mini-dsl
  527. #.Parameter name
  528. #       The attribute name
  529. #.Parameter value
  530. #  The attribute value
  531. Param([Parameter(Mandatory=$true)]$name,[Parameter(Mandatory=$true)]$value)
  532.    New-Object XAttribute $name, $value
  533. }
  534. Set-Alias xa New-XAttribute
  535. Set-Alias New-XmlAttribute New-XAttribute
  536.  
  537.  
  538. function New-XElement {
  539. #.Synopsys
  540. #       Creates a new XElement (an xml tag for XDocument)
  541. #.Description
  542. #  This is the work-horse for the XML mini-dsl
  543. #.Parameter tag
  544. #       The name of the xml tag
  545. #.Parameter args
  546. #       this is where all the dsl magic happens. Please see the Examples. :)
  547. Param(
  548.    [Parameter(Mandatory = $true, Position = 0)]
  549.    [System.Xml.Linq.XName]$tag
  550. ,
  551.    [Parameter(Position=99, Mandatory = $false, ValueFromRemainingArguments=$true)]
  552.    [PSObject[]]$args
  553. )
  554. BEGIN {
  555.         if([string]::IsNullOrEmpty( $tag.NamespaceName )) {
  556.                 $tag = $($script:NameSpaceStack.Peek()) + $tag
  557.       if( $script:NameSpaceStack.Count -gt 0 ) {
  558.          $script:NameSpaceStack.Push( $script:NameSpaceStack.Peek() )
  559.       } else {
  560.          $script:NameSpaceStack.Push( $null )
  561.       }      
  562.         } else {
  563.       $script:NameSpaceStack.Push( $tag.Namespace )
  564.         }
  565. }
  566. PROCESS {
  567.   New-Object XElement $(
  568.      $tag
  569.      while($args) {
  570.         $attrib, $value, $args = $args
  571.         if($attrib -is [ScriptBlock]) {
  572.            &$attrib
  573.         } elseif ( $value -is [ScriptBlock] -and "-Content".StartsWith($attrib)) {
  574.            &$value
  575.         } elseif ( $value -is [XNamespace]) {
  576.            New-Object XAttribute ([XNamespace]::Xmlns + $attrib.TrimStart("-")), $value
  577.         } else {
  578.            New-Object XAttribute $attrib.TrimStart("-"), $value
  579.         }
  580.      }
  581.    )
  582. }
  583. END {
  584.    #if(![string]::IsNullOrEmpty( $tag.NamespaceName )) {
  585.       $null = $script:NameSpaceStack.Pop()
  586.    #}
  587. }
  588. }
  589. Set-Alias xe New-XElement
  590. Set-Alias New-XmlElement New-XElement
  591.  
  592. Export-ModuleMember -alias * -function New-XDocument, New-XAttribute, New-XElement, Remove-XmlNamespace, Convert-Xml, Select-Xml, Format-Xml

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