Insert XML node from template

This topic contains 5 replies, has 2 voices, and was last updated by Profile photo of Dave Wyatt Dave Wyatt 2 years, 4 months ago.

  • Author
    Posts
  • #17390
    Profile photo of Rob Simmers
    Rob Simmers
    Participant

    Trying to insert a node from a template into a loaded XML document. I'm getting the following error:

    Exception calling "AppendChild" with "1" argument(s): "The specified node cannot be inserted as the valid child of this node
    , because the specified node is the wrong type."

    The end goal would be to add a {param} with {name}Blah{/name} with a for loop. If the XML has an existing parameter, I can clone that and do a for loop, but if no child node exists I would like to copy a node from a template and then I assume it would be just cloning. I cannot, however, figure out how to insert the node from the template:

    [xml]$template = '
        {param}
    	    {name}{/name}
            {other}{/other}
       {/param}
    '
    
    [xml]$xmlExample = @"
    {?xml version="1.0"?}
    {job}
        {parameters}
        {/parameters}
    {/job}
    "@
    
    $jobParameters = $xmlExample.SelectSingleNode("//parameters")
    $jobParameters.AppendChild($template.Clone())

    Also, to make this as "real world" as possible, the XML does not even have an opening parameter tag. So, the file I'm working with look more like:

    [xml]$xmlExample = @"
    {?xml version="1.0"?}
    {job}
    {/parameters}
    {/job}
    "@

    which Powershell doesn't like with this error.

    Error: "The 'job' start tag on line 2 position 2 does not match the end tag of 
    'parameters'. Line 3, position 7."

    I'm just trying to get to this:

    {?xml version="1.0"?}
    {job}
        {parameters}
            {param}
    	        {name}{/name}
                {other}{/other}
           {/param}
        {/parameters}
    {/job}

    Edit: Website eats XML, so replaced standard tags with {}

  • #17391
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Try this:

    $jobParameters = $xmlExample.SelectSingleNode("//parameters")
    $null = $jobParameters.AppendChild($xmlExample.ImportNode($template.param, $true))
    

    Couple of things here. You can't append an element that came from a different Document object, but that's what the ImportNode method is for. Also, you can't import a Document ([xml]), but you can import a node from within that document, such as $template.param .

  • #17392
    Profile photo of Rob Simmers
    Rob Simmers
    Participant

    @Dave, That did work. Thank you for the quick turn around. Any insight on the XML tag that doesn't start. I see a lot of tags that do it in this XML and get the aforementioned error. Granted, I can open the file and do a simple replace, but didn't know if there was a preferred method with XML dom. Thank you again.

  • #17393
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    I'm not sure what you're talking about. The XML you posted with no opening parameters tag is invalid, and I haven't come across this in any documents. You do, on the other hand, frequently see self-closing tags like this:

    {parameters /} 

    instead of

     {parameters}{/parameters}
  • #17409
    Profile photo of Rob Simmers
    Rob Simmers
    Participant

    Thanks for you assistance. The self closing tags are similar to HTML. Last question (for this post), I see numerous methods to nullify the output from methods

    $null = $jobParameters.AppendChild($xmlExample.ImportNode($template.param, $true))
    #or
    [void]$jobParameters.AppendChild($xmlExample.ImportNode($template.param, $true))
    #or
    $jobParameters.AppendChild($xmlExample.ImportNode($template.param, $true)) | Out-Null

    The all accomplish the same thing, but does one work better or preferred over the other?

  • #17410
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    They do all accomplish the same thing, but piping to Out-Null is much slower than the other two. I tend to use assignments to $null, but that's just personal preference. If you cast to [void], sometimes you have to put an extra set of parentheses around the pipeline that's producing the results, whereas sticking "$null = " at the beginning of a pipeline always works.

You must be logged in to reply to this topic.