Power Automate - Cloud Flow - Using xpath for parent node attributes - xpath

A RESTful API call returns the XML noted below.
I need to loop through various steps for each ShowSurveyAnswerKey. So in this case, 8 of them. Got that working with an "Apply to each" step expression of:
xpath(xml(body('HTTP_Get')),'//ShowSurveyAnswer')
In that "Apply to each", need to know values of ShowSurveyKey, ShowSurveyQuestionKey and ShowSurveyAnswerKey. The only one I can get working is ShowSurveyAnswerKey, which I happen to be testing with an action "Compose" with expression of:
xpath(item(),'string(/ShowSurveyAnswer/#ShowSurveyAnswerKey)')
So really, I can't figure out the parent or ancestor or ../ within Power Automate Compose Expression within the "Apply to each".
All help much appreciated. Thanks!
<?xml version="1.0" encoding="utf-8"?>
<Show ShowKey="123" >
<ShowSurveys>
<ShowSurvey ShowSurveyKey="230151" >
<SurveyQuestions>
<SurveyQuestion ShowSurveyQuestionKey="842125" >
<SurveyAnswers>
<ShowSurveyAnswer ShowSurveyAnswerKey="3316719" />
<ShowSurveyAnswer ShowSurveyAnswerKey="3316720" />
<ShowSurveyAnswer ShowSurveyAnswerKey="3316721" />
</SurveyAnswers>
</SurveyQuestion>
</SurveyQuestions>
</ShowSurvey>
<ShowSurvey ShowSurveyKey="217418" >
<SurveyQuestions>
<SurveyQuestion ShowSurveyQuestionKey="808668" >
<SurveyAnswers>
<ShowSurveyAnswer ShowSurveyAnswerKey="3192170" />
<ShowSurveyAnswer ShowSurveyAnswerKey="3192174" />
</SurveyAnswers>
</SurveyQuestion>
<SurveyQuestion ShowSurveyQuestionKey="808669" >
<SurveyAnswers>
<ShowSurveyAnswer ShowSurveyAnswerKey="3192175" />
<ShowSurveyAnswer ShowSurveyAnswerKey="3192176" />
<ShowSurveyAnswer ShowSurveyAnswerKey="3192177" />
</SurveyAnswers>
</SurveyQuestion>
</SurveyQuestions>
</ShowSurvey>
</ShowSurveys>
</Show>

Related

Debatching in xmlDisassembler using envelope schema, failing on empty message

I am debatching an incoming xml messages in BizTalk receive pipeline using an envelope schema. The debatching works well for any xml that contains the sub message I am trying to debatch but fails if the message does not contain any sub message.
I have set the "min occurs" to 0 and nillable = true in the schema for the elements that are in the xpath for debatching. In the sample below the "entry" and "resource" elements have min occurs set to 0, which I thought would let the debatching function work when there is nothing to be debatched.
Here is the annotation for the envelope schema.
<xs:annotation>
<xs:appinfo>
<schemaInfo xmlns="http://schemas.microsoft.com/BizTalk/2003" is_envelope="yes"/>
</xs:appinfo>
</xs:annotation>
<xs:element name="Bundle">
<xs:annotation>
<xs:appinfo>
<recordInfo xmlns="http://schemas.microsoft.com/BizTalk/2003" body_xpath="/*[local-name()='Bundle' and namespace-uri()='']/*[local-name()='entry' and namespace-uri()='']/*[local-name()='resource' and namespace-uri()='']"/>
</xs:appinfo>
</xs:annotation>
Example message with no messages to debatch
<Bundle >
<type value="searchset"/>
<total value="0"/>
</Bundle>
Example of xpath for debatching when sub messages are present.
<Bundle >
<type value="searchset"/>
<total value="46"/>
<entry>
<resource>
<Encounter>
Any message that contains the entry/resource/encounters element debatches successfully, but the messages that do not contain the "entry" element ( has no messages to debatch) throw the error below.
Reason: This Disassembler cannot retrieve body nodes using this XPath: "/[local-name()='Bundle' and namespace-uri()='']/[local-name()='entry' and namespace-uri()='']/[local-name()='resource' and namespace-uri()='']".
/[local-name()='Bundle' and namespace-uri()='']/[local-name()='entry' and namespace-uri()='']/[local-name()='resource' and namespace-uri()='']
I would expect the messages with nothing to debatch to simply "disappear", but instead I end up with an error in group hub. Any ideas or suggestion on how to get rid of this error would be greatly appreciated.
You can use below body_xpath to extract only the 'Bundle' with 'entry' records
body_xpath="/*[local-name()='Bundle' and namespace-uri()=''][*[local-name()='entry' and namespace-uri()=''][count(*)>0]]/*[local-name()='entry' and namespace-uri()='']/*[local-name()='resource' and namespace-uri()='']"
or
body_xpath="/*[local-name()='Bundle' and namespace-uri()=''][*[local-name()='entry' and namespace-uri()=''][count(*)>0]]/*[local-name()='entry' and namespace-uri()='']/*[local-name()='resource' and namespace-uri()='']"
That is because you are pointing the body at the resource node, which does not even exists when there is no message to debatch. You need to be pointing at the a node that always exists in the envelope under which the body messages occur.
What you probably need is the following for emtpy
<Bundle >
<type value="searchset"/>
<total value="0"/>
<entries/>
</Bundle>
and the following for messages.
<Bundle >
<type value="searchset"/>
<total value="46"/>
<entries>
<entry>
<resource>
<Encounter>
And point your body_xpath at entries.

UnauthorizedAccessException on pdb trying to debug a unit test

If I put a single breakpoint on this method, on the last line, and debug via "Debug selected tests" in the Test Explorer, I get an UnauthorizedAccessException on the pdb of the test assembly and the test aborts.
module Tests
open System
open Xunit
[<Fact>]
let fact () =
let rng = Random ()
let a = rng.Next() % 2 = 0
let b = rng.Next() % 2 = 0
a && b // <- breakpoint here
If I put a breakpoint anywhere else, I can debug fine. I can put a breakpoint on that line and debug if there's a breakpoint somewhere else in the method; the last breakpoint just appears empty (no generated code matches it). Note that the && on the last line seems important, if I remove it the problem goes away. For example this version doesn't exhibit the problem:
[<Fact>]
let fact () =
let rng = Random ()
let a = rng.Next() % 2 = 0
let b = rng.Next() % 2 = 0
let result = a && b
result // can put a breakpoint anywhere and debug fine
I could not repro outside a particular solution containing many other projects that I work on, even using all the exact same references and App.config. I spent already quite some time trying to nail down the issue and am looking for tips at this point. Here they are anyway:
App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="xunit.methodDisplay" value="method"/>
</appSettings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="xunit.core" publicKeyToken="8d05b1bb7a6fdb6c" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.1.0.3179" newVersion="2.1.0.3179" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.4.0.0" newVersion="4.4.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
packages.config:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FSharp.Core" version="4.0.0.1" targetFramework="net46" />
<package id="xunit" version="2.1.0" targetFramework="net46" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net46" />
<package id="xunit.assert" version="2.1.0" targetFramework="net46" />
<package id="xunit.core" version="2.1.0" targetFramework="net46" />
<package id="xunit.extensibility.core" version="2.1.0" targetFramework="net46" />
<package id="xunit.extensibility.execution" version="2.1.0" targetFramework="net46" />
<package id="xunit.runner.visualstudio" version="2.1.0" targetFramework="net46" />
</packages>
Visual Studio Enterprise 2015 Update 3 (Version 14.0.25424.00)
It's a bit of guesswork, but the a && b is an expression rather than a statement, so the breakpoint doesn't get hit.
If the test runner has made a shadow copy of your assembly and PDB, then it might try to delete it after the test completes - but the debugger is still accessing it, leading to the exception.
Assuming you are on the same bitness (using 32bit xunit runner for a 32 bit project), I'm guessing the reason this is breaking is because unit tests should have signature: unit -> unit or in C# terms void.
If you change your first example to return unit, I was able to debug a && b with no issues. Now as to why your second example works even though it has the same return type, I have no idea. Maybe the bug is related to needing to assign a variable to be able do stuff with it in xunit?
[<Fact>]
let fact () =
let rng = Random ()
let a = rng.Next() % 2 = 0
let b = rng.Next() % 2 = 0
a && b // <- breakpoint here works
()

SI <int-xml:xpath-filter /> behavior

I have a scenario where I am filtering a xml payload based on a xpath value.
<int:channel id="documentReceiptFilterChannel" />
<int:chain input-channel="documentReceiptFilterChannel" output-channel="nullChannel">
<!-- Filter to discard message if <statusCode> value is 'EMLOK' -->
<int-xml:xpath-filter match-type="regex" match-value="^(?!\bEMLOK\b).*$" discard-channel="nullChannel">
<int-xml:xpath-expression expression="//*[local-name()='statusCode']" />
</int-xml:xpath-filter>
<int:service-activator expression="#opsLogger.logError('TransactionId=' + headers.correlationId, ' Msg=' + #opsExceptionUtils.createOPSExceptionInstance(#root))" />
</int:chain>
Following is the payload:
<?xml version="1.0" encoding="UTF-8"?>
<GetDocumentReceiptReply xmlns="http://example.org"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<mergeReceiptDeliveryStatus>
<statusCode>EMLOK</statusCode>
</mergeReceiptDeliveryStatus>
</GetDocumentReceiptReply>
My requirement is that when <statusCode>EMLOK</statusCode> element is available, discard the message and hence nullChannel is mentioned as discard-channel.
But then there is any other value, proceed to the next step in the chain and do the error logging - <int:service-activator expression="#opsLogger.logError().
The above setup works fine as long as <statusCode> element is present in the payload. But doesn't work on the following situations:
<statusCode></statusCode>
<statusCode/>
<statusCode> is missing
Or any other xml payload
To get rid of namespace issues, the xpath expression is formed as <int-xml:xpath-expression expression="//*[local-name()='statusCode']" />. The xpath value is matched against regex expression match-type="regex" match-value="^(?!\bEMLOK\b).*$" (For value != 'EMLOK').
What happens when <int-xml:xpath-expression /> evaluation fails?
My only requirement is that if <statusCode>EMLOK</statusCode> is present, discard the message, else for all other, log an error in the log file. (And not to throw an exception that will propagate to error-channel).
You could write a custom subclass of AbstractXPathMessageSelector and delegate to a BooleanTestXPathMessageSelector and a RegexTestXPathMessageSelector, or simply use 2 filters...
<int:chain input-channel="documentReceiptFilterChannel" output-channel="errors">
<int-xml:xpath-filter discard-channel="errors">
<int-xml:xpath-expression expression="//*[local-name()='statusCode']" />
</int-xml:xpath-filter>
<int-xml:xpath-filter match-type="regex" match-value="^(?!\bEMLOK\b).*$">
<int-xml:xpath-expression expression="//*[local-name()='statusCode']" />
</int-xml:xpath-filter>
</int:chain>
<int:service-activator
expression="#opsLogger.logError('TransactionId=' + headers.correlationId, ' Msg=' + #opsExceptionUtils.createOPSExceptionInstance(#root))" />
Notice that you don't need to discard to nullChannel - just omitting the discard channel will cause discards. Messages that pass the second filter go to the chain's output channel.
The custom selector would be a little more efficient because only one conversion to node is needed.

Wix - How to remove the parent set of nodes using XmlConfig and Xpath

How do i find a text() node in XmlConfig and use it to remove the parent nodeset. All the examples I have seen just find and remove the 'found' node not the parent nodes.
My understanding is that this Xpath finds the matching node via verify path and ElementPath is the path of the nodes to remove. However Its not working at all.
Is text() supported?, I have tried [[*='ATrigger'[]], [[].='ATrigger'[]] but still no luck.
<util:XmlConfig Id="RemoveATriggerCompletely" File="[#QuartzXmlJob]" Sequence="104" Action="delete" On ="install" Node="element"
ElementPath="//job-scheduling-data/schedule/"
VerifyPath="//job-scheduling-data/schedule/trigger/cron/name[\[]text()='ATrigger'[\]]"/>
Given the following XML
<job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">
<schedule>
<trigger>
<cron>
<name>ATrigger</name>
<group>default</group>
<description>Every 2 minutes</description>
<job-name>ATriggerJob</job-name>
<job-group>defaultGroup</job-group>
<misfire-instruction>SmartPolicy</misfire-instruction>
<!-- every 5mins -->
<cron-expression>2 * * * * ?</cron-expression>
</cron>
</trigger>
<trigger>
<cron>
<name>BTrigger</name>
<group>default</group>
<description>Every 2 minutes</description>
<job-name>BTriggerJob</job-name>
<job-group>defaultGroup</job-group>
<misfire-instruction>SmartPolicy</misfire-instruction>
<!-- every 5mins -->
<cron-expression>2 * * * * ?</cron-expression>
</cron>
</trigger>
The output i require is
<job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">
<schedule>
<trigger>
<cron>
<name>BTrigger</name>
<group>default</group>
<description>Every 2 minutes</description>
<job-name>BTriggerJob</job-name>
<job-group>defaultGroup</job-group>
<misfire-instruction>SmartPolicy</misfire-instruction>
<!-- every 5mins -->
<cron-expression>2 * * * * ?</cron-expression>
</cron>
</trigger>
I have been banging my head against a wall for hours now so any help whatsoever is very much appreciated.
I'm not familiar with that "XmlConfig" task.
But I see two issues.
You need to alias the namespace and use that alias for the xpath "select".
I show the XmlPeek version below. Note I use "peanut", you can use any alias name you want.
Note the query now has "peanut:" in all the element names.
<!-- you do not need a namespace for this example, but I left it in for future reference -->
<XmlPeek Namespaces="<Namespace Prefix='peanut' Uri='http://quartznet.sourceforge.net/JobSchedulingData'/>"
XmlInputPath=".\Parameters.xml"
Query="//peanut:job-scheduling-data/peanut:schedule/peanut:trigger/peanut:cron/peanut:name[text()='ATrigger']/../..">
<Output TaskParameter="Result" ItemName="Peeked" />
</XmlPeek>
Note my "../.."
Once you find the correct element, finding its parent(s) is simple as the ".." notation.
You'll need to figure out how to add the namespace and alias to your Task (XmlConfig)
APPEND:
http://sourceforge.net/p/wix/bugs/2384/
Hmmm...dealing with a namespace isn't trivial. I think you're having a similar issue to what is reported there.
APPEND:
"Inline" Namespacing ... (Yuck)
<XmlPeek
XmlInputPath=".\Parameters.xml"
Query="//*[local-name()='job-scheduling-data' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='schedule' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='trigger' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='cron' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='name' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData'][text()='ATrigger']/../..">
<Output TaskParameter="Result" ItemName="Peeked" />
</XmlPeek>
Aka, try this Xpath:
"//*[local-name()='job-scheduling-data' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='schedule' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='trigger' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='cron' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData']/*[local-name()='name' and namespace-uri()='http://quartznet.sourceforge.net/JobSchedulingData'][text()='ATrigger']/../.."

Get children and subchildren together?

I am using lxml library in python and I am working with xpath.I have a an xml file example as follows:
<Root>
<Child1 name="child1">
<Child2 name="child2" />
</Child1>
<Child3 name="child3">
<Child4 name="child4" />
</Child3>
<Child5 name="child5" />
</Root>
i need to know if there is a way to get all children at once like child1,child2,child3,child4 at once... currently I am able to get only child1, child3, child5 using root.xpath('node()')

Resources