0

In this xml, i have to filter tag <controlTask> id values which matches to my stringArray $myStringArray (using powershell)

if matches, traverse into it and find <myflow:eventBooster> with event="start" and replace script content with $startContent1, and find event="end" replace with $endContent1

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns:myflow="http://myflow.google.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="POC">
   <thread id="JALSA_KUSHI_ONLY" name="JALSA ONLY" isFine="true" myflow:isOk="true">
      <docprocess>My Doc Process</docprocess>
      <extensionElements>
         <myflow:historyLevel><![CDATA[audit]]></myflow:historyLevel>
      </extensionElements>
      <controlTask id="ReadDoc1" name="Read Doc" myflow:type="http">
         <extensionElements>
            <myflow:field name="rnhAsJson">
               <myflow:string><![CDATA[true]]></myflow:string>
            </myflow:field>
            <myflow:eventBooster event="start" class="org.abc.SecureJavascripteventBooster">
               <myflow:scriptInfo scriptType="javascript" script="&quot;use strict&quot;;var loaded={require:require,exports:{}};" />
            </myflow:eventBooster>
            <myflow:eventBooster event="end" class="org.abc.SecureJavascripteventBooster">
               <myflow:scriptInfo scriptType="javascript" script="&quot;use strict&quot;;var loaded={require:require,exports:{}},pending={};function require(e,t){define(void 0,e,t)};" />
               <myflow:field name="language">
                  <myflow:string><![CDATA[javascript]]></myflow:string>
               </myflow:field>
            </myflow:eventBooster>
         </extensionElements>
      </controlTask>
      <JimmyGate id="MyWish" name="My own" />
      <controlTask id="WriteDoc1" name="write task" myflow:type="http">
         <extensionElements>
            <myflow:field name="requestMethod">
               <myflow:string><![CDATA[POST]]></myflow:string>
            </myflow:field>
            <myflow:eventBooster event="start" class="org.abc.SecureJavascripteventBooster">
               <myflow:scriptInfo scriptType="javascript" script="&quot;use strict&quot;;" />
            </myflow:eventBooster>
            <myflow:eventBooster event="end" class="org.abc.SecureJavascripteventBooster">
               <myflow:scriptInfo scriptType="javascript" script="&quot;use strict&quot;;var loaded={require:require}" />
            </myflow:eventBooster>
         </extensionElements>
      </controlTask>
      <JimmyGate id="sid-iquweiq-1uy1-8173eu-817e81ye" />
   </thread>
</definitions>

I have controltaskId, but unable to traverse into it. But getting all the data matching with <controlTask>, <myflow:eventBooster>

$xmldata =( Select-Xml -Path $location\xyz.xml -XPath / ).Node;

$controltaskId = $xmldata.definitions.thread.controlTask.GetAttribute("id");

can someone please help here

1
  • 1
    $xmldata.definitions.thread.controlTask resolves to an array of both <controlTask> nodes. You'll want to do something like foreach($controlTaskNode in $xmldata.definitions.thread.controlTask){ "This particular controlTask node has id '$($controlTaskNode.GetAttribute('id'))'"} Commented Aug 23, 2022 at 10:48

2 Answers 2

3

Here is a possible solution:

$xmldata.definitions.thread.controlTask.Where{ $_.id -in $myStringArray }.ForEach{
   $_.extensionElements.eventBooster.Where{ $_.event -eq 'start' }.ForEach{
       $_.scriptInfo.script = $startContent1
   }
   $_.extensionElements.eventBooster.Where{ $_.event -eq 'end' }.ForEach{
       $_.scriptInfo.script = $endContent1
   }
}
  • $xmldata.definitions.thread.controlTask gives us an array of all controlTask elements. Similarly, $_.extensionElements.eventBooster gives us an array of all eventBooster elements from the current extensionElements. See member access enumeration for how this works.
  • Use PowerShell intrinsic method .Where{} for filtering of arrays (alternatively use the Where-Object command).
    • Applied to .controlTask, filter by id attribute that is contained in $myStringArray.
    • Applied to .eventBooster, filter for matching event attribute.
  • PowerShell's intrinsic method .ForEach{} is used to iterate over the filtered element (alternatively use the ForEach-Object command). The syntax of the intrinsic methods is more concise and they perform better than the command alternatives so I prefer them for processing data structures (and not output of other commands).
Sign up to request clarification or add additional context in comments.

Comments

1

Try following :

using assembly System 
using assembly System.Linq
using assembly System.Xml.Linq 

$inputFilename = "c:\temp\test.xml"
$outputFilename = "c:\temp\test1.xml"
$xDoc = [System.Xml.Linq.XDocument]::Load($inputFilename)
$root = [System.Xml.Linq.XElement]$xDoc.Root
#Write-Host "root = " $root
$ns = [System.Xml.Linq.XNamespace]$root.GetNamespaceOfPrefix("myflow")
$eventBoosters = $xDoc.Descendants($ns + "eventBooster")
$starts = [System.Linq.Enumerable]::Where($eventBoosters, [Func[object,bool]]{ param($x) [string]$x.Attribute("event").Value -eq "start"})
foreach($start in $starts)
{
   [System.Xml.Linq.XElement]$start.SetAttributeValue("event", '$startContent1')
}
$ends = [System.Linq.Enumerable]::Where($eventBoosters, [Func[object,bool]]{ param($x) [string]$x.Attribute("event").Value -eq "end"})
foreach($end in $ends)
{
   [System.Xml.Linq.XElement]$end.SetAttributeValue("event", '$endContent1')
}
$xDoc.Save($outputFilename)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.