using mule variable value in xpath expression - xpath

I have a variable set as
<set-variable variableName="productIdvar" value="#[xpath://productId]" doc:name="Variable" />
On logging its coming right,
I want to use the value of the variable productIdvar in my xpath expression,
<when expression="//*[local-name()='itemid']=?" evaluator="xpath">
or
<when expression="#[xpath://*[local-name()='itemid']=?]">
What should i use in place of ? to get the value of the variable?
Thanks
Rahul.

The following expression should work for you.
<when expression="#[xpath('//*[local-name()=\'itemid\']').text == productIdvar ]">
This way you should be able to compare the result of the xpath with the "productIdVar" variable.
Hope this helps.

<when expression="#[xpath('//*[local-name()=itemid]') == productIdvar ]">
Note that there are no quotation marks surrounding itemid in expression

If your MEL gets a bit messy, try my mule-module-dxpath - an XPath transformer which dynamicaly resolves XPath variables.

You can use XPATH3 and try something like this
#[xpath3('/products/validlity')== flowVars.productIdvar]
Xpath3 reference :- https://developer.mulesoft.com/docs/display/current/XPath

Related

Spark SQL (Databricks) function xpath ignores empty tags in XML

Spark SQL (Databricks) function xpath ignores empty tags in XML. For example for below XML XPATH returns array ["ABC"]. We need it as ["ABC", NULL or empty string] because when we use this along with posexplode_outer, omitting null in XPATH will cause incorrect association.
Is there any option in XPATH to retain nulls? I did not find any detailed documentation for this.
SELECT xpath("<PARTY>
<PARTY_EVENT>
<EVENTTYPE>VISITED</EVENTTYPE>
<LOCATION>ABC</LOCATION>
</PARTY_EVENT>
<PARTY_EVENT>
<EVENTTYPE>VISITED</EVENTTYPE>
<LOCATION />
</PARTY_EVENT>
</PARTY>"
, '/PARTY/PARTY_EVENT/LOCATION/text()')
Add the nodes not containing any text by using [not(text())] selector:
(/PARTY/PARTY_EVENT/LOCATION|/PARTY/PARTY_EVENT/LOCATION[not(text())])/text()

Using Variable in Node Attribute

I am writing a XSL template. I am not getting how to specify a variable for a custom attribute inside XSL file.
I am trying this code in XSL:
<xsl:variable name="var1" select="DEF"/>
<frequency myAttr="ABC"+$var1 >
<xsl:value-of select="frequency"/>
</frequency>
Expected result is
<frequency myAttr="ABCDEF" >20</frequency>
I am getting this error:
Unable to generate the XML document using the provided XML/XSL input. org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 24; Element type "sourceId" must be followed by either attribute specifications, ">" or "/>"
The issue is the way I am concatenating is wrong. Any help in achieving this?
I think you mean :
<frequency myAttr="ABC{$var1}" >
This will concatenate the literal string "ABC" with the content of the $var1 variable - see: Attribute Value Templates.
Note that the way you populate the variable suggests there is an element named DEF in the source XML. The expected result will be obtained only if this element has a string value of "DEF".
XSL is a declarative language in XML format. An XSLT file must be well-formed XML.
What you tried looks like you have programming knowledge of an imperative language where you can write expressions like "ABC" + $var1. This violates the XML format rules in XSL however. Elements follow the pattern <elementname attribute1="value1" attributeN="valueN">...</elementname>. In your code, you put +$var1 after the end of the myAttr attribute, which ends at the second quote mark - and this is invalid: <frequency myAttr="ABC"+$var1 >
<frequency myAttr="ABC+$var1"> would result in a literal attribute value of ABC+$var1, which is not what you want. This would also happen if you tried to use XPath syntax as attribute value, concat('ABC', $var1) as string from <frequency myAttr="concat('ABC', $var1)">.
You can use the Attribute Value Template syntax as michael.hor257k suggested, which essentially means to wrap XPath expressions in curly braces inside of attribute value strings.
Another way would be to not write the element as literal in your code, but rather declare it:
<xsl:variable name="var1" select="'DEF'"/>
<xsl:element name="frequency">
<xsl:attribute name="myAttr">
<xsl:value-of select="concat('ABC', $var1)"/>
</xsl:attribute>
</xsl:element>
Note that I corrected the variable definition: In the select attribute, you must put DEF in single quote marks if this is supposed to be a string, like select="'DEF'". Without the single quote marks you define the variable to refer to <DEF> elements in the source XML.
In the select attribute of <xsl:value-of> I used the XPath function concat() to concatenate the string 'ABC' and the content of the variable $var1. The attribute value template syntax can not be used here: select="'ABC{$var1}'" would result in the string ABC{$var1}.
A variation of above example would be to use <xsl:text> for the string ABC and <xsl:value-of> to output the content of $var1:
<xsl:variable name="var1" select="'DEF'"/>
<xsl:element name="frequency">
<xsl:attribute name="myAttr">
<xsl:text>ABC</xsl:text>
<xsl:value-of select="$var1"/>
</xsl:attribute>
</xsl:element>
So there are three solutions, a concise one and two declarative ones. Which one you choose is up to you. The quickest to type is certainly the first:
<xsl:variable name="var1" select="'DEF'"/>
<frequency myAttr="ABC{$var1}">
<xsl:value-of select="frequency"/>
</frequency>
... but you should also be aware of both declarative ways to achieve the same result and understand how they work.

Ruby regular expressions with html tags

If I have a string that is this
<f = x1106f='0'>something
and The values inside <> can change How would I use regular expressions to isolate "something" and replace the tag?
EDIT:
<(.*?)> Pattern worked
What you need is
string =~ />([^<]+)/
and the something will be captured in $1.
Use the following regex to capture "something":
(?<=>)(.*?)(?=<)
assuming that after "something" there's a closing tag.
Link to fiddle

Determine if any element with a given name has a particular value

Given this XML fragment (I've removed superfluous fluff):
<Event name="DataComplete">
<Task id="d20a0053-7678-43ba-bc8a-ece24dcff15b"/>
<DataItems>
<DataItem name="Survey" type="task">
<Value status="NotStarted" taskId="00000000-0000-0000-0000-000000000000" />
</DataItem>
<GroupDataItem name="CT_Visit"> --- this may repeat
<ItemGroup id="1" >
<DataItem name="Special Contractor" type="string">Yes</DataItem>
What xPath expression will determine if any DataItem with name="Special Contractor" has the value "Yes".
I'm trying something like this:
Yes = /Event/Task/DataItems/GroupDataItem/ItemGroup/DataItem/#[normalize-space() = 'Special Contractor']
and many variations usually resulting in "invalid xPath expression".
Any clues most welcome. Thanks!
[EDIT]
Thanks for the answers Jiri and Will. Will was close, but as my question states, I'm trying to determine if any* element has the value Yes. I should have been more explicit in saying that I need a boolean, true or false. Adapting Will's answer led me to this:
"Yes" = //Event/Task/DataItems/GroupDataItem/ItemGroup/DataItem[#name='Special Contractor']
This returns a simple Boolean='true' or Boolean='false'.
Thanks guys!
/Event/DataItems/GroupDataItem/ItemGroup/DataItem[#name = "Special Contractor"][. = "Yes"]
Returns the DataItem in question. Note that this will be a sequence of matching DataItem elements if there are more than one. If you just want a boolean:
exists(/Event/DataItems/GroupDataItem/ItemGroup/DataItem[#name = "Special Contractor"][. = "Yes"])
(as an aside; I removed Task from the xpath, since it's not actually an ancestor of the DataItem in the XML fragment you posted, even though the indentation makes it look like it is.)
Use this xpath
/Event/Task/DataItems/GroupDataItem/ItemGroup/DataItem[#name='Special Contractor']
for following xml:
<Event name="DataComplete">
<Task id="d20a0053-7678-43ba-bc8a-ece24dcff15b">
<DataItems>
<DataItem name="Survey" type="task">
<Value status="NotStarted" taskId="00000000-0000-0000-0000-000000000000" />
</DataItem>
<GroupDataItem name="CT_Visit"> --- this may repeat
<ItemGroup id="1" >
<DataItem name="Special Contractor" type="string">Yes</DataItem>
</ItemGroup>
</GroupDataItem>
</DataItems>
</Task>
...
</Event>
If the task is really non-pair element, then omit it from the xpath expression.

XPath query to match depending on combinations of child elements

I have the following Xml structure; Payment/Line which has amongst its element a IsFeePayment and a IsServiceProduct elements of type bool.
<Payment>
<Line>
<IsFeePayment>true</IsFeePayment>
<ISServiceProduct>true</IsServiceProduct>
</Line>
</Payment>
i want an xpath statement that returns 'true' when both of these are are they are, true.
if either one is false, i want the xpath statement to return 'false'
THe xpath below is almost there, it returns the line when both are true.
/[local-name()='Payment']/[local-name()='Line'][*[local-name()='IsFeePayment'][text()='true'] and *[local-name()='IsServiceProduct'][text()='true']]
how do i just get a simple bool out instead of the whole element?
You can simplify the xpath to
boolean(//Payment/Line[IsFeePayment='true' and IsServiceProduct='true'])
simply adding a boolean() around the xpath expression i already had fixes the problem blush
so ...
boolean(/[local-name()='Payment']/[local-name()='Line'][*[local-name()='IsFeePayment'][text()='true'] and *[local-name()='IsServiceProduct'][text()='true']])

Resources