I am trying to understand difference between cts:element-query, cts:element-value-query and cts:element-word-query using cts:search().
When someone can achieve the same thing using all three why did they created these many?
I am sure I am missing something here to understand. I have following data:
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
<CD>
<TITLE>Greatest Hits</TITLE>
<ARTIST>Dolly Parton</ARTIST>
<COUNTRY>EU</COUNTRY>
<COMPANY>RCA</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1982</YEAR>
</CD>
</CATALOG>
I want to filter the data for country say "EU". I can achieve the same thing with any query listed below.
cts:search(//CD,cts:element-query(xs:QName("COUNTRY"),"EU"))
cts:search(//CD,cts:element-value-query(xs:QName("COUNTRY"),"EU"))
cts:search(//CD,cts:element-word-query(xs:QName("COUNTRY"),"EU"))
So what is the difference? When to use what? Can someone help me understand?
My understand was to use cts:search with cts:element-query. I was researching with the other queries if I can get the same thing using other queries too. (I have gone thru the documentation I still don't understand). Can someone please give me a simple explanation?
Those three cts:element-* query functions have some overlapping functionality, and it is possible to get the same results, but there are some key differences that affect what is possible and how efficient the query may be for your system.
cts:element-query() is a container query. It matches the element specified in the first parameter. The query from second parameter is applied to the matched element and all of its descendants. So the cts:word-query would match the text of COUNTRY or any descendant elements, if there were a more complex structure.
Using xdmp:plan() to see the query plan,
xdmp:plan(cts:search(//CD,cts:element-query(xs:QName("COUNTRY"),"EU")))
you can see the plan has criteria with an unconstrained word-query being applied:
<qry:term-query weight="1">
<qry:key>17785254954065741518</qry:key>
<qry:annotation>word("EU")</qry:annotation>
</qry:term-query>
cts:element-value-query() only matches against simple elements (that is, elements that contain only text and have no element children) with text content matching the phrase from the second parameter.
The xdmp:plan() for that query:
xdmp:plan( cts:search(//CD,cts:element-value-query(xs:QName("COUNTRY"),"EU")) )
reveals that there is a value being applied specifically to the COUNTRY element:
<qry:term-query weight="1">
<qry:key>9358511946618902997</qry:key>
<qry:annotation>element(COUNTRY,value("EU"))</qry:annotation>
</qry:term-query>
cts:element-word-query() is similar to a cts:element-value-query except that it searches only through immediate text node children of the specified element as well as any text node children of child elements defined in the Admin Interface as element-word-query-throughs or phrase-throughs. It does not search through any other children of the specified element.
The xdmp:plan() for that query:
xdmp:plan( cts:search(//CD,cts:element-word-query(xs:QName("COUNTRY"),"EU")) )
shows that there is a word query applied specifically to the COUNTRY element:
<qry:term-query weight="1">
<qry:key>6958980695756965065</qry:key>
<qry:annotation>element(COUNTRY,word("EU"))</qry:annotation>
</qry:term-query>
cts:element-word-query is most helpful if you had mixed content and a known vocabulary of specific elements that you want to be able to "see through" when searching. One example is MS Word or XHTML markup in which there are elements wrapping text that are used for applying styling and formatting, such as <b>, <i>, and <u> inside of a <p> and you wanted to search for a word in a given paragraph and search through the b, i, and u child elements.
For this specific instance, looking to search for a value in a specific element, you should use:
cts:search(//CD,cts:element-value-query(xs:QName("COUNTRY"),"EU"))
It is the most specific and efficient means of telling MarkLogic that you want to search for the value "EU" in the COUNTRY element (and not any of it's children or descendants).
Related
I am currently working on a web app and I need to query a data attribute that repeatedly shows up in a table.
In the table that I declare a data-test-id attribute that I can use later for testing. One example:
<td data-test-id="table-element-1-9:0-cell"> Hello world!<td>
I am querying the data attributes with a css selector for testing. The only thing that changes with each use of the data-test-id attribute are the three numbers which I will replace with X here:
/* css selector */
.select('[data-test-id="table-element-X-X:X-cell"]')
How do I create a regular expression to match all of the other characters is this attribute while ignoring the numbers denoted by X (as in the number denoted by X can be any number from 0-9)?
I tried using the following but it doesn't seem to work:
/\[data-test-id="table-element-[0-9]-[0-9]:[0-9]-cell"\]/g
Well AFAIK there is no regex-matching attribute selector in CSS. You could instead use a broader selector of
[data-test-id^="table-element-"][data-test-id$="-cell"]
This matches all elements with a data-test-id attribute that starts with table-element- and ends in -cell. Of course that might not be specific enough depending on the possible values of that attribute.
If that is the case, you could further filter the elements that are returned by above query using whatever language you call the select function from. For example using the regex you provided above.
I would like to have a query that looks at the name of its parent and then will navigate to the folder with the same sitename underneath the content folder and show the items underneath it in the multilist.
Basically the structure in the content tree looks as followed:
sitecore
content
Sitename1
(items that needs to be showed in the multilist)
Sitename2
(items that needs to be showed in the multilist)
medialibrary
Sitename1
PDF1 (with multiList with search)
Sitename2
PDF2 (with multiList with search)
Trouble starts when I would like to start comparing the "name" of the relative parent to the "name" of the child of the absolute path. In Xpath it would probably go something like it is described within: Compare attribute values using Xpath
In this case I had the following query up until now:
/sitecore/content/*[ancestor-or-self::*[##templateid='{Template Id of Sitename}']=##name and ##templateid='{Template Id of Sitename}']
This query returns Sitename1 and Sitename2.
Funny thing is that if I replace "ancestor-or-se.." or "##name" part bij "Sitename1", like so:
/sitecore/content/*['Sitename1'=##name and ##templateid='{Template Id of Sitename}']
..and..
/sitecore/content/*[./ancestor-or-self::*[##templateid='{Template Id of Sitename}']='DSW' and ##templateid='{Template Id of Sitename}']
I get the wanted result: Sitename1.
Btw I'm using the build-in xpath builder for now, before it paste the query into the "multilist with search."
Any help would be appreciated.
Edit:
I think I found out that when I start the relative query (the "./ancestor::..." part) it actually is relative to the item where I ended up with the absolute query. So I should have the following query:
./ancestor-or-self::*[##templateid='{Template Id of Sitename}' and ##name=ancestor::*[##templateid='{Template Id of root item aka "sitecore"}']//*[##templateid={Template Id of Sitename}]]
Here I get the error "Object must be of type String," which is probably because of the following part of the previous query:
##name=ancestor::*[##templateid='{Template Id of root item aka "sitecore"}']//*[##templateid={Template Id of Sitename}]
The right part of this doesn't solve to a string. So the question remains, how to extract pure the string out of a sitecore item using sitecore xpath in order to be able to make a comparison.
I figured out that Sitecore doesn't support subqueries at least for fast queries, I think same applies to normal ones (see also: "Subqueries are not supported" in here ). Which now lead me to using simple code where I perform two queries. A very simple way to do it is to inherit from IDatasource (in the sitecore.buckets.dll), you will need to write "code:{fullpath to class}, assemblyname.dll" (See also: here)
I'm pretty sure this doesn't exist, but I wonder if anyone has done this kind of thing as an add-on for CSS.
Let's say we have an XML document containing the Code of Federal Regulations (CFR), and also say that the document itself cannot be edited (all we can do is use a style sheet to display it), and let's say that there is a subpart which contains multiple rules, and the XML document is roughly as follows:
<subpart>
<ruleNo>63.400</ruleNo>
<ruleTitle>Definitions</ruleTitle>
<ruleNo>63.410</ruleNo>
<ruleTitle>Applicability</ruleTitle>
...
</subpart>
Now I would like to write a stylesheet that puts the subpart content into a table, with rule numbers on the left column and rule titles on the right column. The task would be much easier if there were a way to select an adjacent ruleNo and ruleTitle as if they corresponded to a single node, and then write a rule for that imaginary node.
For example, there could be a node-defining functor => which would temporarily define as a node the part in braces. For example, Rule => subpart > {ruleNo + ruleTitle} would create a temporary node which would be the parent of any pair of siblings ruleNo + ruleTitle which were children of subpart.
CSS does not support manipulating the document tree, nor does it offer an ability to group element nodes in the manner that you describe. Additionally, the CSS2.1 table model does not offer a way to apply styles such that every ruleNo + ruleTitle pair can be formatted as an individual row: while CSS has a concept of anonymous boxes that can be created as ancestors or descendants, which also extends to the table model, it does not support generating a single anonymous box that acts as the parent row of a pair of ruleNo + ruleTitle cells at a time.
Preprocessor languages such as Sass and LESS are irrelevant as they're compiled into CSS anyway, so if it's not doable with CSS then neither is it doable with a preprocessor.
Given your current XML, it's not possible to use CSS to format it into a table with each row containing a ruleNo and a ruleTitle element. You'll want to use XSLT to transform it into an XHTML table with the corresponding rows instead.
I've been able to compile the CLucene project on iOS and am currently trying to use it within my iOS application. I'm trying to index xhtml documents, and have been able to do that by extracting the text nodes out of those documents, and then index in lucene by concatenating them together, so as to all the text from one xhtml doc appears in a single Lucene document.
However, each text node of my xhtml document has custom attributes to it, so that when a search is made on the indexed text, I should be also be able to obtain the attribute associated with that text.
My xml data looks like:
<span data-value="/1/2/3">This is a sample text for this span</span>
<span data-value="/2/3/4">This is a example text for another span</span>
<span data-value="/3/4/5">Searching for this span text</span>
So when I search from the Lucene index for a word sample, then I should be able to retrieve the data-value attributed to the word Sample is associated. In the case above it will be data-value="/1/2/3".
The way I'm creating an index is by concatenating the data-value attribute and the text node field together, and then have it indexed by Lucene. This way, whenever my search results return, then it would also return the data-value attributed along with it. I can evaluate the attribute value, and at the time of searching will strip away this attribute from the display results altogether. However, this is not true for large text contained in a span text, where in the searched word(s) may be returned but the data-value attributes may not be part of the search results, which can further be stripped off while display.
However, I think this is not the optimal way of indexing XML attributes along with their text data.
I'd appreciate if someone can help me with the approach in order to index the relationship between the text and its attributes.
Update: I found that the tokens generated from the text can have payloads associated with them, so I'm thinking that if we can have the XML attribute built in as a payload for my entire string, which can be treated as a single token (if I don't analyze the text), can be useful for my purpose. I wanted to know if anyone can help me in figuring out if this is the right approach for my case. Many thanks for your help.
Thanks & regards,
Asheesh
If you want to keep all of XHTML text as one Lucene document, then payloads are probably the way to go.
An alternate approach is to create a document ID field (like "documentID:42" and a field denoting that this Lucene document is the whole document concatenated together (like "AllOfDocument:42"). This would let you index each text node individually and limit the attributes to just the attributes for that node, while still tying that text node to whole document. With that approach, you could put the attributes in their own field in the text node Lucene document rather than having to use payloads. Might be simpler.
Even though I am going to use this CSS selector in Selenium, this should be generic enough.
I have a page with table of class "list" & it can occur multiple times. I want to find out each occurrence & how many rows each table has. So for this I could use table[class='list'] & will give me all the tables of that class in the page. In this example lets us say it is 3. Now I want to iterate through each of those table, so I tried table[class='list']:nth-child(1) for the first occurrence & table[class='list']:nth-child(2) for second occurrence & so on. I thought that table[class='list']:nth-child(1) would give me the first occurrence but I cannot use the nth-child(n) notation.
If I use table[class='list']:nth-child(odd), I do get all the odd numbered table, but I cannot specifically target a specific table by saying table[class='list']:nth-child(3). It gives me no result back. What am I doing wrong?
BTW, I am using "FireFinder" addon for Firebug to evaluate my CSS selectors on the test page.
table[class='list']:nth-child(1) will match all table elements with a class of list that are the first child of their parent. It has nothing to do with how many elements are matched or what the order of that set is, though if all the tables had the same parent (and that parent had no other children) then your method would work.
You may be able to iterate through the elements returned by table.list some other way, or somehow change your selector the exact details of which would depend on the actual structure of your page.
Perhaps XPath would suit you better?
//table[#class='list' and position()=1]
//table[#class='list' and position()=2]
...