PoshCode Logo PowerShell Code Repository

Select-Xml 2.1 (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/1503"></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.

  1. #requires -version 2.0
  2. # Select-Xml 2.1 and Remove-XmlNamespace
  3.  
  4. function Select-Xml {
  5. #.Synopsis
  6. #  This improved version of 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.
  7. #
  8. #  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.  
  9. #
  10. #  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.
  11. #.Parameter Content
  12. #  Specifies a string that contains the XML to search. You can also pipe strings to Select-XML.
  13. #.Parameter Namespace
  14. #   Specifies a hash table of the namespaces used in the XML. Use the format @{<namespaceName> = <namespaceUri>}.
  15. #.Parameter Path
  16. #   Specifies the path and file names of the XML files to search.  Wildcards are permitted.
  17. #.Parameter Xml
  18. #  Specifies one or more XML nodes to search.
  19. #.Parameter XPath
  20. #  Specifies an XPath search query. The query language is case-sensitive. This parameter is required.
  21. #.Parameter RemoveNamespace
  22. #  Allows the execution of XPath queries without namespace qualifiers.
  23. #  
  24. #  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.
  25. #
  26. #  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.
  27. [CmdletBinding(DefaultParameterSetName="Xml")]
  28. PARAM(
  29.    [Parameter(Position=1,ParameterSetName="Path",Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
  30.    [ValidateNotNullOrEmpty()]
  31.    [Alias("PSPath")]
  32.    [String[]]$Path
  33. ,
  34.    [Parameter(Position=1,ParameterSetName="Xml",Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  35.    [ValidateNotNullOrEmpty()]
  36.    [Alias("Node")]
  37.    [System.Xml.XmlNode[]]$Xml
  38. ,
  39.    [Parameter(ParameterSetName="Content",Mandatory=$true,ValueFromPipeline=$true)]
  40.    [ValidateNotNullOrEmpty()]
  41.    [String[]]$Content
  42. ,
  43.    [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]
  44.    [ValidateNotNullOrEmpty()]
  45.    [Alias("Query")]
  46.    [String[]]$XPath
  47. ,
  48.    [Parameter(Mandatory=$false)]
  49.    [ValidateNotNullOrEmpty()]
  50.    [Hashtable]$Namespace
  51. ,
  52.    [Switch]$RemoveNamespace
  53. )
  54. BEGIN {
  55.    function Select-Node {
  56.    PARAM([Xml.XmlNode]$Xml, [String[]]$XPath, $NamespaceManager)
  57.    BEGIN {
  58.       foreach($node in $xml) {
  59.          if($NamespaceManager -is [Hashtable]) {
  60.             $nsManager = new-object System.Xml.XmlNamespaceManager $node.NameTable
  61.             foreach($ns in $Namespace.GetEnumerator()) {
  62.                $nsManager.AddNamespace( $ns.Key, $ns.Value )
  63.             }
  64.          }
  65.          
  66.          foreach($path in $xpath) {
  67.             $node.SelectNodes($path, $NamespaceManager)
  68.    }  }  }  }
  69.  
  70.    [Text.StringBuilder]$XmlContent = [String]::Empty
  71. }
  72.  
  73. PROCESS {
  74.    $NSM = $Null; if($PSBoundParameters.ContainsKey("Namespace")) { $NSM = $Namespace }
  75.  
  76.    switch($PSCmdlet.ParameterSetName) {
  77.       "Content" {
  78.          $null = $XmlContent.AppendLine( $Content -Join "`n" )
  79.       }
  80.       "Path" {
  81.          foreach($file in Get-ChildItem $Path) {
  82.             [Xml]$Xml = Get-Content $file
  83.             if($RemoveNamespace) {
  84.                $Xml = Remove-XmlNamespace $Xml
  85.             }
  86.             Select-Node $Xml $XPath  $NSM
  87.          }
  88.       }
  89.       "Xml" {
  90.          foreach($node in $Xml) {
  91.             if($RemoveNamespace) {
  92.                $node = Remove-XmlNamespace $node
  93.             }
  94.             Select-Node $node $XPath $NSM
  95.          }
  96.       }
  97.    }
  98. }
  99. END {
  100.    if($PSCmdlet.ParameterSetName -eq "Content") {
  101.       Select-Node (Remove-XmlNamespace ([Xml]($XmlContent.ToString()))) $XPath  $NSM
  102.    }
  103. }
  104.  
  105. }
  106.  
  107.  
  108.  
  109.  
  110. function Remove-XmlNamespace {
  111. #.Synopsis
  112. #  Removes namespace definitions and prefixes from xml documents
  113. #.Description
  114. #  Runs an xml document through an XSL Transformation to remove namespaces from it if they exist.
  115. #  Entities are also naturally expanded
  116. #.Parameter Content
  117. #  Specifies a string that contains the XML to transform.
  118. #.Parameter Path
  119. #  Specifies the path and file names of the XML files to transform. Wildcards are permitted.
  120. #
  121. #  There will bne one output document for each matching input file.
  122. #.Parameter Xml
  123. #  Specifies one or more XML documents to transform
  124. #
  125. [CmdletBinding(DefaultParameterSetName="Xml")]
  126. PARAM(
  127.    [Parameter(ParameterSetName="Content",Mandatory=$true)]
  128.    [String[]]$Content
  129. ,
  130.    [Parameter(Position=0,ParameterSetName="Path",Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
  131.    [Alias("FullName")]
  132.    [String[]]$Path
  133. ,
  134.    [Parameter(Position=0,ParameterSetName="Xml",Mandatory=$true,ValueFromPipeline=$true)]
  135.    [Alias("IO","InputObject")]
  136.    [System.Xml.XmlDocument[]]$Xml
  137. )
  138. BEGIN {
  139.    $xslt = New-Object System.Xml.Xsl.XslCompiledTransform
  140.    $xslt.Load(([System.Xml.XmlReader]::Create((New-Object System.IO.StringReader @"
  141. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  142.   <xsl:output method="xml" indent="yes"/>
  143.   <xsl:template match="/|comment()|processing-instruction()">
  144.      <xsl:copy>
  145.         <xsl:apply-templates/>
  146.      </xsl:copy>
  147.   </xsl:template>
  148.  
  149.   <xsl:template match="*">
  150.      <xsl:element name="{local-name()}">
  151.         <xsl:apply-templates select="@*|node()"/>
  152.      </xsl:element>
  153.   </xsl:template>
  154.  
  155.   <xsl:template match="@*">
  156.      <xsl:attribute name="{local-name()}">
  157.         <xsl:value-of select="."/>
  158.      </xsl:attribute>
  159.   </xsl:template>
  160. </xsl:stylesheet>
  161. "@))))
  162. }
  163. PROCESS {
  164.    switch($PSCmdlet.ParameterSetName) {
  165.       "Content" {
  166.          [System.Xml.XmlDocument[]]$Xml = @( [Xml]($Content -Join "`n") )
  167.       }
  168.       "Path" {
  169.          [System.Xml.XmlDocument[]]$Xml = @()
  170.          foreach($file in Get-ChildItem $Path) {
  171.             $Xml += [Xml](Get-Content $file)
  172.          }
  173.       }
  174.       "Xml" {
  175.       }
  176.    }
  177.    foreach($input in $Xml) {
  178.       $Output = New-Object System.Xml.XmlDocument
  179.       $writer =$output.CreateNavigator().AppendChild()
  180.       $xslt.Transform( $input.CreateNavigator(), $null, $writer )
  181.       $writer.Close() # $writer.Dispose()
  182.       Write-Output $output
  183.    }
  184. }
  185. }

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