Search code examples
xpathxquerycontainsexists

How to use not contains with attributes and elements


<newproducts>
        <number id ="1">
        <number id ="2">
        <number id ="3">
        <number id ="4">
        <number id ="5">
</newproducts>    
<products>   
        <number>2</number>
        <number>3</number>
        <number>4</number>
</products>

number id contains 2, 3, 4 so the output should be like this

<number>1</number>
<number>5</number>

because 1 and 5 are not in number id so I want to output them

Why does this not work?

for $z in /newproducts/number[@id/string() != /products/number/text()]
return 
<number>{$z}</number>

Is this possible with the contains function or exists or even a if then else ?


Solution

  • The != operator is effectively "is there at least one item in the sequence that is different." If you need to effectively check "are there no items in the sequence that are the same" then use:

    not(@id/string = /products/number/text())
    

    instead of

    @id/string() != /products/number/text()
    

    Try reworking as follows (I wrapped your input with a root node and corrected some typos along the way here):

    let $list :=
        <list>
        <newproducts>
                <number id ="1"/>
                <number id ="2"/>
                <number id ="3"/>
                <number id ="4"/>
                <number id ="5"/>
        </newproducts>    
        <products>   
                <number>2</number>
                <number>3</number>
                <number>4</number>
        </products>
        </list>
    return
    for $z in $list/newproducts/number[not(@id/string() = $list/products/number/text())]
    return <number>{$z}</number> 
    

    That returns:

    <number>
      <number id="1"/>
    </number>
    <number>
      <number id="5"/>
    </number>
    

    But your expected output doesn't have number enclosed in number, so change your return clause from

    <number>{$z}</number>  
    

    to something like:

    <number>{$z/@id/string()}</number>  
    

    for example:

    ...
    for $z in $list/newproducts/number[not(@id/string() = $list/products/number/text())]
    return <number>{$z/@id/string()}</number>  
    

    which returns

    <number>1</number>
    <number>5</number>