Lets say this is the XML file I have.
<bookstore>
<book year="1994">
<title>blah</title>
<price>66</price>
</book>
<book year="1998">
<title>blahblah</title>
<price>99</price>
</book>
</bookstore>
How do I select all books where the year attribute is <1995 and price is <70.
This is what I have:
for $x in doc("bkstr.xml")/bookstore/book
where $x/price<70 and ??
return $x
How do i check the value of the year attribute?
Attributes are addressed by using #.
for $x in doc("bkstr.xml")/bookstore/book
where $x/price<70 and $x/#year<1995
return $x
You can also use the much shorter equivalent
doc("bkstr.xml")/bookstore/book[price<70 and #year<1995]
Related
How could I get the list of title books where country location is unique in the next XML?
<BooksLib>
<Book Title="Murder in NY" Year="1980">
<BookLocations>
<Location City="New York" Country="USA"/>
<Location City="Virginia" Country="USA"/>
</BookLocations>
</Book >
<Book Title="Dracula" Year="2000">
<BookLocations>
<Location City="Sydney" Country="Australia"/>
<Location City="Moab" Country="USA"/>
<Location City="Calvados" Country="France"/>
</BookLocations>
</Book>
<Book Title="Romance in calvados" Year="2012">
<BookLocations>
<Location City="Calvados" Country="France"/>
</BookLocations>
</Book >
</BooksLib>
For example, in this XML would be "Dracula", because Australia only appears once
Now I got this:
for $book in doc("books.xml")//Book
where count(distinct-values($Book/BookLocations/Location/#Country)) eq 1
return $Book/data(#Title)
But this gives me the titles where the county is the same.
I would do it slightly differently. First, because it feels more natural to me how one actually thinks and second, because it will be faster on a large set. So first I would try to identify which countries are just present once. And then based on this filter out the results. The following should work:
let $single-loc :=
for $loc in doc("books.xml")//Location/#Country/string()
where count(//Location/#Country[. = $loc]) = 1
return $loc
for $book in doc("books.xml")//Book
where $book/BookLocations/Location/#Country = $single-loc
return $book/data(#Title)
Please note, that your input XML was not well-formed (I edited your post). Also, your XQuery is wrong as $book and $Book are two different variables.
I have an assignment to create an xml file and query it using XQuery. The file looks roughly like this:
<library>
<book>
<title>Title1</title>
<author>Author1</author>
<author>Author2</author>
<subject>Subject1</subject>
</book>
<book>
<title>Title2</title>
<author>Author3</author>
<subject>Subject1</subject>
</book>
</library>
For each author, I'm supposed to return the title of the book, so obviously Title 1 should be returned twice.
I've been trying something like this:
let $a:=doc("/home/user/library.xml")/library/book
for $x in $a/title, $y in $a/author
return $x
The results I'm getting are:
Title1
Title2
Title1
Title2
Title1
Title2
I see that the problem is that for every author, I'm returning every book title, but I'm not sure how to get it to return only the book titles that correspond to a particular author. Any suggestions?
Thanks!
Use:
for $author in distinct-values(/*/*/author)
return
/*/book[$author = author]/title/string()
When this XPath expression (that is also XQuery, because XPath is a subset of XQuery) is evaluated against the provided XML document:
<library>
<book>
<title>Title1</title>
<author>Author1</author>
<author>Author2</author>
<subject>Subject1</subject>
</book>
<book>
<title>Title2</title>
<author>Author3</author>
<subject>Subject1</subject>
</book>
</library>
the wanted, correct result is produced:
Title1 Title1 Title2
A chapter-metadata.xml store in each book isbn folder(there are 100 isbn folder so there is 100 chapter-metadata.xml) which store in marklogic database server and chapter-metadata. Xml either contain data of one chapter or empty. If chapter-metadata.xml contain only one chapter information then I want to add more chapter information(my chapter infomation is common for all chapter) under chapter element with attribute and value of that chapter up to how many chapter store in book isbn folder(that I can fetch and store in a variable $chapter_sequence like ch001 ch002 ch003 ch004..) or if chapter-metadata.xml does not have any chaper information then it will create chapter element with attribute and value of chapter number and add my information, below I have put some xml structure if there is one chapter information and my information is from element keywordset
<?xml version="1.0" encoding="UTF-8" ?>
<chaptermetadata>
<bookisbn>isbn number</bookisbn>
<booktitle>Copyright</booktitle>
<chapter id="ch001"">
<keywordset>
<keyword role="primary">context</keyword>
<keyword role="secondary">Copyright</keyword>
<keyword role="tertiary">subject</keyword>
</keywordset>
</chapter>
</chaptermetadata>
I want like below:
<?xml version="1.0" encoding="UTF-8" ?>
<chaptermetadata>
<bookisbn>isbn number</bookisbn>
<booktitle>Copyright</booktitle>
<chapter id="ch001"">
<keywordset>
<keyword role="primary">context</keyword>
<keyword role="secondary">Copyright</keyword>
<keyword role="tertiary">subject</keyword>
</keywordset>
</chapter>
<chapter id="ch002"">
<keywordset>
<keyword role="primary">context</keyword>
<keyword role="secondary">Copyright</keyword>
<keyword role="tertiary">subject</keyword>
</keywordset>
</chapter>
so on to last chapter which I store in veriable
</chaptermetadata>
thanks,
raj
The question is hard to follow, but start with http://docs.marklogic.com/xdmp:directory and a FLWOR expression. Let's say you put this into a function. I'll handwave a few helper functions that you would also have to implement, but the function might look something like this:
declare function chaptermetadata($isbn as xs:string)
as element(chaptermetadata) {
<chaptermetadata>
{
<bookisbn>{ $isbn }</bookisbn>
<booktitle>{ title($isbn) }</booktitle>
for $chapter in xdmp:directory(isbn-uri($isbn), 'infinity')
return element { fn:node-name($chapter) } {
$chapter/#*,
$chapter/keywordset }
}
<chaptermetadata>
};
Now, this code won't help much unless you understand everything that it's doing so you can modify it to suit your needs. This is a variation on one of the XQuery use cases, so you might find helpful to work through and understand those: http://www.w3.org/TR/xquery-use-cases/
Is there any way to check for existence of list of elements in xml document? The element names are stored in sequence, If the xml document contains any of the elements (names stored in sequence) then return YES otherwise return NO. I tried below example and it did not work.Any suggestion please?
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
let $doc:=doc("book.xml")/book
let $fields := ('title','author')
return
if(doc/*:$fields)
then
"YES"
else "NO"
Try this
return
if($fields[not(.=$doc/*/name())]
then
"No"
else "YES"
Use:
if(/*/*/name() = ('title', 'author'))
then 'YES'
else 'NO'
Or, alternatively:
('YES'[$doc/*/*/name() = $fields], 'NO')[1]
Using Xquery, how can I search the file below (consisting of many items), for all items with 'XC' in the part-number (there are many), then for matches return all 3 of the interesting data elements (part-number, part-name, and name)? The return is the main problem--my attempts result in every permutation of the interesting data elements. Thank you!
<catalog>
<item>
<description>
<partref>
<part-id>
<part-number>XC51222</part-number>
</part-id>
</partref>
<part-name>DSP, Network Vectoring<part-name>
<vendors>
<vendor1>
<pay-to>
<name>JCOF Industries</name>
</pay-to>
</vendor1>
</vendors>
</description>
</item>
<item>
</item>
[many items…]
</catalog>
xquery version "1.0";
let $sep := ','
for $x in catalog/item
where fn:matches($x/description/partref/part-id/part-number, 'XC')
return fn:string-join( ($x/description/partref/part-id/part-number/text(), $x/description/part-name/text(), $x/description/vendors/vendor1/pay-to/name/text()), $sep)