How to tell using XPath if an element is present and non empty?

72,452

Solution 1

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.

Solution 2

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/>.

Solution 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()]

Solution 4

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

Solution 5

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

<expression-filter
    expression="#[xpath('count(//Holding/Policy/PolNumber/child::text())') != 0]"/>
Share:
72,452
Charu Khurana
Author by

Charu Khurana

Java enthusiast, currently Mule consultant

Updated on May 30, 2020

Comments

  • Charu Khurana
    Charu Khurana about 4 years

    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>
    
  • Charu Khurana
    Charu Khurana about 11 years
    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
    Charu Khurana about 11 years
    I changed above expression to <expression-filter expression="#[xpath('fn:count(//acord:Holding/acord:Policy/a‌​cord:PolNumber)') != 0]"/> and that worked, however, for <PolNumber/> count is non zero just like boolean function
  • David Dossot
    David Dossot about 11 years
    Strange you have to prefix with fn. Edit your question and show how is your namespace manager configured please.
  • David Dossot
    David Dossot about 11 years
    Thanks, I think includeConfigNamespaces is what's screwing the default namespace and forces to prefix with fn. Do you really need it?
  • David Dossot
    David Dossot about 11 years
    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.
  • Charu Khurana
    Charu Khurana about 11 years
    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
    Charu Khurana about 11 years
    Now, with text child nodes, it works for all the scenarios. Thank you very much
  • Charu Khurana
    Charu Khurana about 11 years
    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 <Holding><Policy><PolNumber></PolNumber><Policy></Holding>. I don't know how to show a new line in comment but my intent was to have new line character between <PolNumber> and </PolNumber>
  • Dimitre Novatchev
    Dimitre Novatchev about 11 years
    @Learner, This is straight-forward: boolean(//acord:Holding/acord:Policy/acord:PolNumber/text()[‌​normalize-space()][1‌​])
  • Charu Khurana
    Charu Khurana about 11 years
    Thanks Dimitre. I don't have exposure with xpath, all this is very helpful to me.
  • JGFMK
    JGFMK about 5 years
    This should have been the accepted answer in my eyes. boolean(//a/node()) on <a></a> gives false. Whereas <a><b/></a> gives true. Try it out here: freeformatter.com/xpath-tester.html. boolean(//a/text()[1]) yields false under both those scenarios.