21

I have an input XML something on this line:

<Holding id="12">
    <Policy>
        <HoldingForm tc="1">Individual</HoldingForm>
        <PolNumber>848433</PolNumber>
        <LineOfBusiness tc="1">Life</LineOfBusiness>
        <CarrierCode>67644</CarrierCode>
    </Policy>
</Holding>

My manipulation on this XML depends on if <PolNumber> (its an optional element in schema) has a value or not. I'm using Mule 3.3 xpath evaluator to do this and my XPath expression looks this:

<expression-filter expression="#[xpath('//acord:Holding/acord:Policy/acord:PolNumber').text != empty]"/> 

This works fine as long as <PolNumber> element is present or <PolNumber/> is empty element. But if <PolNumber> is absent, above expression throws exception.

I tried using XPath boolean function but it returns true for <PolNumber/>. Is there a better way of checking if an element is present and non-empty?

EDIT:

This is the configuration of namespace manager in my mule config

<xm:namespace-manager includeConfigNamespaces="true">
    <xm:namespace prefix="acord" uri="http://ACORD.org/Standards/Life/2" />
    <xm:namespace prefix="soap" uri="http://schemas.xmlsoap.org/soap/encoding/" />
</xm:namespace-manager>
Jens Erat
  • 37,523
  • 16
  • 80
  • 96
Charu Khurana
  • 4,511
  • 8
  • 47
  • 81

5 Answers5

30

Use:

boolean(//acord:Holding/acord:Policy/acord:PolNumber/text()[1])

this produces true() if //acord:Holding/acord:Policy/acord:PolNumber has a first text-node child, and false() otherwise.

Do note: This is more efficient than counting all text-node children just to compare the count with 0.

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • I agree this is better than counting all text-node children but even this solution is not full-proof. this xpath will return true for ``. I don't know how to show a new line in comment but my intent was to have new line character between `` and `` – Charu Khurana Apr 10 '13 at 16:39
  • 2
    @Learner, This is straight-forward: `boolean(//acord:Holding/acord:Policy/acord:PolNumber/text()[normalize-space()][1])` – Dimitre Novatchev Apr 10 '13 at 17:22
  • 1
    Thanks Dimitre. I don't have exposure with xpath, all this is very helpful to me. – Charu Khurana Apr 10 '13 at 18:07
13

You can use boolean(...) for checking if it's empty, but make sure to look inside the element.

boolean(//PolNumber/node())

This also works if other nodes are contained. If you want to limit to text nodes, replace node() by text(). You could want to use //text() instead, then the query will also yield true for text nodes inside other child elements of <PolNumber/>.

Jens Erat
  • 37,523
  • 16
  • 80
  • 96
  • This should have been the accepted answer in my eyes. `boolean(//a/node())` on `` gives false. Whereas `` gives true. Try it out here: https://www.freeformatter.com/xpath-tester.html. `boolean(//a/text()[1])` yields false under both those scenarios. – JGFMK May 27 '19 at 11:42
3

Maybe I'm a bit late here, but answers are a bit confusing. This one will always returns false when text is blank or with spaces but no chars.

boolean//Holding/Policy/PolNumber/child/text()[normalize-space()]
Kamil Budziewski
  • 22,699
  • 14
  • 85
  • 105
Thomas Modeneis
  • 687
  • 8
  • 11
2

What about using count to get the number of text nodes:

<expression-filter
    expression="#[xpath('count(//Holding/Policy/PolNumber/child::text())') != 0]"/>
David Dossot
  • 33,403
  • 4
  • 38
  • 72
  • Thank you for your response. `No Such Function {http://www.mulesoft.org/schema/mule/core}:count (org.jaxen.UnresolvableException) org.jaxen.SimpleFunctionContext:127` exception is thrown for count function. – Charu Khurana Apr 09 '13 at 18:31
  • I changed above expression to `` and that worked, however, for `` count is non zero just like `boolean` function – Charu Khurana Apr 09 '13 at 18:43
  • Strange you have to prefix with `fn`. Edit your question and show how is your namespace manager configured please. – David Dossot Apr 09 '13 at 18:43
  • 2
    Thanks, I think `includeConfigNamespaces` is what's screwing the default namespace and forces to prefix with `fn`. Do you really need it? – David Dossot Apr 09 '13 at 18:48
  • I've reviewed by answer to count the number of text child nodes in PolNumber. You may need to prefix with `fn:` in your config. – David Dossot Apr 09 '13 at 18:53
  • I don't need `includeConfigNamespaces` attribute really. Removing it caused function to work without `fn` prefix. Thanks for pointing that. Don't think I'd be able to catch it. – Charu Khurana Apr 09 '13 at 18:59
  • Now, with text child nodes, it works for all the scenarios. Thank you very much – Charu Khurana Apr 09 '13 at 19:00
2

How about expression="#[?xpath('//acord:Holding/acord:Policy/acord:PolNumber').text != empty]" ? This should work in in all situations