Dealing only with Current Child Nodes

Please see attached script and XML. This was originally built to handle a JEHEADER ->JELINE structure with one JEHEADER per file. Got a new file for testing today, and it had multiple instances of JEHEADER -> JELINE. So Now, I have data I need to inject into JELINE from JEHEADER from only the current JEHEADER->JELINE.

There are five instances of JEHEADER->JELINE in this attached XML and the data I am injecting from the headers get injected 5 times on each JELINE.

So how do I stay on only the current JEHEADER -> JELINE?

If someone could take a look it would be really helpful

Here’s your basic code structure, trimmed down:

$nodes = $PY.SelectNodes("//JEHEADER")

foreach ($node in $nodes)
    #JE Description
    $DESC = $node.SelectNodes(".//DESCRIPTN") |
            Select-Object -ExpandProperty InnerXML
    $JEID = $node.SelectNodes(".//JEID") |
            Select-Object -ExpandProperty InnerXML

    # Go into each node
    $nodes = $PY.SelectNodes(".//JELINE") 

    foreach ($node in $nodes)
        # Do stuff

    echo $file

The main problem here is that you’re calling $PY.SelectNodes(".//JELINE") instead of $node.SelectNodes(".//JELINE") . It’s also a little odd to be redefining the $node and $nodes variable inside a foreach loop that uses both of those names. Though it technically doesn’t break anything in PowerShell, it’s still hard to follow. I’d use different variable names in each of the loops. (Perhaps something like foreach ($headerNode in $headerNodes) and foreach ($lineNode in $lineNodes) ).

It’s also a bit strange to have “echo $file” and “$PY.Save($file)” inside your foreach loop. Those lines probably belong outside the loops, unless you really intend to save the file after each iteration.

As always, thank you for your rapid responses. They are most helpful. I am new to this and it is most appreciated. I realize the scripts are odd, and that is mainly because they are not production quality, its me experimenting and getting comfortable.

ok - I have one more question, and this pushes me over the finish line on this project. Please see attached. As you can see there are many places where I am injecting an Element into an existing node:

$e = $PY.CreateElement("ORIGREF")

I am doing this type of operation while I am in an existing node, which I have set with $PY.SelectNodes

I have a new requirement in which I would have to inject some Elements and set InnerText on a node I will be creating in flight. Is that possible? If so - how would it look?

Something along these lines?

$newpayline = $PY.CreateElement(“PAYLINE”)

–Which would just add the node at the root of the file - I think $PY would already be at the root, correct? and therefore I am adding a new node at the root, or is there something I have to do before this to set $PY back to the root?


$newelement = $newpayline.CreateElement(“ORIGREF”)

And so forth…

In reviewing the file, the business case is that in the PAYHEADER under USERAREA there are one or more DATASTREAM.EXTCHARGEDISTRIBUTION entries that I need to transform into PAYLINES and append them to the file. Not every field is needed to be cloned from the existing PAYLINE Nodes, I just have to create a new PAYLINE and add the elements I am going to need to work with later on.

So inside of a foreach loop on those PAYHEADER EXTCHARGEDISTRIBUTIONs I would perform the operations to grab all the variables I need (which I have already figured out), and then append a new PAYLINE node and inject the variable values in as necessary in ELEMENTS under the new PAYLINE. So in reference to the XML example file I had, the result would be that 2 PAYLINES are added, and they contain the variable values I grabbed from each EXTCHARGEDISTRIBUTION on the PAYHEADER

Again - is this possible? I am beginning to realize that almost anything is possible with PowerShell, so I hoping this is not a big deal. Do I generally have the right idea, or am I in a different territory when I want to start adding nodes at the root?

Thank you again in advance for all of your assistance.

You’re basically on the right track. All calls to CreateElement() (and similar methods) will be made on your $PY variable, but that doesn’t mean that the elements will be placed at the document root. What matters is which node you call AppendChild() on. I can’t see your XML attachment (it would need to be renamed to .txt), but I still have a copy of an XML sample that you attached to your other thread. In that file, your PAYLINE nodes were all placed under LOAD_PAYABLE_005\DATAAREA\LOAD_PAYABLE , so I’ll assume that’s where you want to put the new payline node in this code. Here’s now that would work:

$loadPayableNode = $PY.SelectSingleNode('/LOAD_PAYABLE_005/DATAAREA/LOAD_PAYABLE')

$newpayline = $PY.CreateElement('PAYLINE')
$null = $loadPayableNode.AppendChild($newpayline)
$newelement = $PY.CreateElement('ORIGREF')
$newelement.InnerText = $InvOrigRef.Node.InnerText.Trim()
$null = $newpayline.AppendChild($newelement)

On a side note, notice that I used the InnerText property instead of calling the set_InnerText method on $newelement. That’s personal preference, I suppose, but most C# and PowerShell code will make use of the Property syntax rather than calling the get_ and set_ methods directly.

I also assigned the results of AppendChild() to $null, to prevent it from polluting the pipeline (or your screen.) Those methods return a reference to the element that was appended, allowing you to chain them together. For example, you could have created the two elements and then inserted them like this:

$null = $loadPayableNode.AppendChild($newpayline).AppendChild($newelement)

Brilliant as always - thank you so much again…

The quality and timeliness of the information I received from this site goes above and beyond what I could have possible imagined when I initially came here. Highly commendable.