Return XML from function

Welcome Forums General PowerShell Q&A Return XML from function

This topic contains 6 replies, has 4 voices, and was last updated by

 
Participant
6 months, 3 weeks ago.

  • Author
    Posts
  • #99567

    Participant
    Points: 0
    Rank: Member

    Hi, I'm trying to write a function which return XML variable.

    function Create-XML()
    {
        [xml]$xml = New-Object System.Xml.XmlDocument
        $Dec = $xml.CreateXmlDeclaration("1.0","UTF-8",$null)
        $xml.AppendChild($Dec)
        $Root = $xml.CreateNode("element","Changes",$null)
        $xml.AppendChild($Root)
        return ,$xml
    }
    

    If I'm trying to use output of this as xml type I'm getting error "Cannot convert value "System.Object[]" to type "System.Xml.XmlDocument""

  • #99613

    Participant
    Points: 141
    Helping Hand
    Rank: Participant

    It's one of those messy things with powershell and functions.
    There is a pretty good explanation in this post (a bit further down):
    understanding output

    To get around your problem either use [void] or pipe the AppendChild statements to Out-Null.
    Otherwise the output of those statements will be added to the output of the function.
    Which will give you an array instead of an XML document.

    E.g.

    function Create-XML()
    {
        [xml]$xml = New-Object System.Xml.XmlDocument
        $Dec = $xml.CreateXmlDeclaration("1.0","UTF-8",$null)
        [void]$xml.AppendChild($Dec)
        $Root = $xml.CreateNode("element","Changes",$null)
        [void]$xml.AppendChild($Root)
        return ,$xml
    }
    
  • #99618

    Participant
    Points: 161
    Helping Hand
    Rank: Participant

    From my prior experimentation with methods of discarding output, I'd recommend a slightly different method.

    Methods from slowest to fastest:

    $Thing | Out-Null # slowest by an order of magnitude
    [void] $Thing
    $null = $Thing
    $Thing > $null # fastest, but only a few ms ahead of the previous
    
  • #99624

    Participant
    Points: 141
    Helping Hand
    Rank: Participant

    Interesting, at aprox. what amount of statements/iterations did you notice the difference?
    Haven't investigated it myself so I guess I haven't run into the problem, that I know of at least.

  • #99625

    Participant
    Points: 161
    Helping Hand
    Rank: Participant

    I tested it with some pretty straightforward stuff, at 10,000 iterations:

    PS C:\WINDOWS\system32> Measure-Command {1..10000 | % {$_ | Out-Null}}
    
    TotalMilliseconds : 601.827
    
    PS C:\WINDOWS\system32> Measure-Command {1..10000 | % {[void]$_}}
    
    TotalMilliseconds : 91.0079
    
    PS C:\WINDOWS\system32> Measure-Command {1..10000 | % {$null = $_}}
    
    TotalMilliseconds : 92.7215
    
    PS C:\WINDOWS\system32> Measure-Command {1..10000 | % {$_ > $null}}
    
    TotalMilliseconds : 91.0059

    So in this particular instance, [void] and > $null worked the same, really. It seems to vary depending on iterations and what kind of things you're discarding, especially with Out-Null. You'll also get slightly different results if you repeat the test a few times, and it tends to average roughly in the order I mentioned, although pretty much any alternative to Out-Null works better than it does.

    Interestingly, doing this actually works pretty quickly as well:

    Out-Null -InputObject $Stuff

    So it's the pipeline that causes the overhead, more than the command. But if you've already got a pipeline spun up, I don't think tacking on Out-Null instead of these other options would really slow things much, in that instance.

  • #99639

    Participant
    Points: 0
    Rank: Member

    When I measure commands like that, I do it a little different to time each execution and average them out. Here are my result. The cmdlet is still slower than the others.

    Test Code

    "Out-Null pipline"
    (1..10000 | % {
        Measure-Command {
            "Test Data" | Out-Null
        }
    } | Measure-Object -Average TotalMilliseconds).Average
    
    "Out-Null cmdlet"
    (1..10000 | % {
        Measure-Command {
            Out-Null -InputObject "Test Data"
        }
    } | Measure-Object -Average TotalMilliseconds).Average
    
    "Void"
    (1..10000 | % {
        Measure-Command {
            [void]"Test Data"
        }
    } | Measure-Object -Average TotalMilliseconds).Average
    
    '$null='
    (1..10000 | % {
        Measure-Command {
           $null = "Test Data"
        }
    } | Measure-Object -Average TotalMilliseconds).Average
    
    'Redirect null'
    (1..10000 | % {
        Measure-Command {
            "Test Data" > $null
        }
    } | Measure-Object -Average TotalMilliseconds).Average
    

    Result 1:

    Out-Null pipline
    0.26157376
    Out-Null cmdlet
    0.261141030000001
    Void
    0.0158285399999992
    $null=
    0.0159924099999991
    Redirect null
    0.0187904100000002

    Result 2:

    Out-Null pipline
    0.258285110000001
    Out-Null cmdlet
    0.25256677
    Void
    0.0159204299999991
    $null=
    0.0173433099999992
    Redirect null
    0.0185149200000002

    Result 3:

    Out-Null pipline
    0.27897332
    Out-Null cmdlet
    0.264224209999999
    Void
    0.0176090299999993
    $null=
    0.0162245199999994
    Redirect null
    0.0187308600000004
  • #99648

    Participant
    Points: 161
    Helping Hand
    Rank: Participant

    Very interesting! I guess either my prior test or my memory (or both!) was flawed.

    I still personally prefer the > $null method syntactically, but it's nice to know that [void] is on par with $null =, if not better.

    $null = Thing doesn't sit super well with me, it's a very odd kind of thing there.

The topic ‘Return XML from function’ is closed to new replies.