سؤال

Below is the XML file -

<Chapters>
  <Chapter>
    <Name>Introduction</Name>
    <Heads>
       <Head>
         <No>1</No>
         <Title>History of Internet</Title>
         <Desc>
         ..............
         </Desc>    
      </Head>
      <Head>
         <No>2</No>
         <Title>History of HTML</Title>
         <Desc>
         ..............
         </Desc>    
      </Head>
    </Heads>
  </Chapter>
  <Chapter>
    <Name>Learn HTML</Name>
    <Heads>
      <Head>
         <No>1</No>
         <Title>Browsers</Title>
         <Desc>
         ..............
         </Desc>    
     </Head>
     <Head>
         <No>2</No>
         <Title>Browser War</Title>
         <Desc>
         ..............
         </Desc>    
     </Head>
     <Head>
         <No>3</No>
         <Title>HTML, DHTML</Title>
         <Desc>
         ..............
         </Desc>    
      </Head>
    </Heads>
  </Chapter>
</Chapters>

I want to list the Chapters/Chapter/Name=Introduction and Chapters/Chapter/Heads/Head/No=1 Following is the query which I am executing in baseX -

/Chapters/Chapter[contains(Name,'Introduction') and contains(Heads/Head/No,'1')]/Heads/Head/Title

And this is the error -

Query: Chapters/Chapter[contains(Name,'Introduction') and contains(Heads/Head/No,'1')]/Heads/Head/Title

Error: [XPTY0004] Single item expected, (element No { ... }, element No { ... }) found.

As per the baseX website, description of the Error XPTY0004 is -

This error is raised if an expression has the wrong type, or cannot be cast into the specified type. It may be raised both statically (during query compilation) or dynamically (at runtime).

What wrong m i doing??

هل كانت مفيدة؟

المحلول

This one would solve the purpose

/Chapters/Chapter[Name='Introduction']/Heads/Head[No='1']/Title

but I cant answer your question... ie I cant explain why your query resulted in error!!

نصائح أخرى

/Chapters/Chapter
   [contains(Name,'Introduction') 
  and 
   contains(Heads/Head/No,'1')
   ]
     /Heads/Head/Title

The first argument of contains() must be a single string but for the second reference to contains() in the above expression, the argument Heads/Head/No evaluates to two elements.

A correction of the expression would be:

/Chapters/Chapter
   [Name[contains(.,'Introduction')]
  and 
   Heads/Head/No[contains(.,'1')]
   ]
     /Heads/Head/Title

Remark: It seems that you actually need to test for equality -- not for containment. This can be expressed in many ways, one of which is:

/Chapters/Chapter
   [Name eq 'Introduction']
  and 
   Heads/Head/No[. eq '1']
   ]
     /Heads/Head/Title

fn:contains($arg1 as xs:string?, $arg2 as xs:string?) as xs:boolean tests if character string $arg2 is contained in $arg1. It expects single strings for each argument (or the empty value ()).

A path step (here: Heads/Head/Title) returns all elements which fit, so all titles of all heads. If you remove the second head of Chapter "Introduction", your query will run successfully.

contains is the wrong way to do this. = compares on a set semantics. Use John's solution or this one which is more close to yours (but John's will be probably faster):

/Chapters/Chapter[Name='Introduction' and Heads/Head/No='1']/Heads/Head/Title

Just a follow-up for the sake of completeness and others coping with the same problem:

Your code will not work, as already pointed out contains does not accept a sequence of strings as its first argument.

(: ssce: :)
let $doc := <doc>
            <a>
              <b>foo</b>
              <b>bar</b>
            </a>
          </doc>
return $doc/a[contains(b, "bar")]

But there is an easy construct to overcome this.

(: ssce, this time working: :)
let $doc := <doc>
            <a>
              <b>foo</b>
              <b>bar</b>
            </a>
          </doc>
return $doc/a[some $b in b/text() satisfies contains($b, "bar")]

These so called quantified expressions (some $var in expr and every $var in expr) are a concise way to express what you are actually doing.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top