Just to explain why Geert's suggestion to add parentheses around 
$song-doc//ts:Value works, this doesn't really have anything to do with 
document vs. sequence order (they're one and the same), but with which 
sequence(s) the predicate (the part in square brackets) is being applied to. 
The key is understanding what "//" is short for: "/descendant-or-self::node()/"

(.//foo)[1] means "get me all descendant <foo> elements and then return just 
the first one" (returning a maximum of one node). In this case, the predicate 
"[1]" applies to the whole (parenthesized) expression to its left.

.//foo[1] means "get me every descendant <foo> element that is the first <foo> 
child of its parent". This expression could return many <foo> elements (which 
is what you were experiencing with all those <ts:Value> elements). In this 
case, the predicate "[1]" is tightly bound to "foo" and applies only to the 
third step of the expression (where the steps are, respectively, ".", 
"descendant-or-self::node()", and "foo[1]").

Like Damon, I'd recommend just using the following-sibling axis if you knew the 
<ts:Value> elements were siblings (and avoiding "//"). But it was clear from 
the behavior that you were experiencing that they aren't siblings. (If you were 
getting all of them, then each must be the first <ts:Value> child of its 
parent.)

To avoid referring to $song-doc//ts:Value more than once, you could store it in 
a variable to avoid the duplication. That also means you don't have to worry 
about adding parentheses anymore (since [$x + 1] filters the whole $values 
sequence and not just one step of the original expression). You mentioned that 
the syntax seemed heavy-handed. Here's a little bit shorter version:

let $values := $song-doc//ts:Value return
for $x in fn:index-of($values,'cat')
return
  $values[$x + 1]/<div class="abc">Value after cat: {string(.)}</div>


Evan Lenz
Software Developer, Community
MarkLogic Corporation

Phone +1 360 297 0087
email  [email protected]<mailto:[email protected]>
web    developer.marklogic.com<http://developer.marklogic.com/>


From: Randy Smith <[email protected]<mailto:[email protected]>>
Reply-To: General MarkLogic Developer Discussion 
<[email protected]<mailto:[email protected]>>
Date: Wed, 11 May 2011 11:59:41 -0700
To: General MarkLogic Developer Discussion 
<[email protected]<mailto:[email protected]>>
Subject: Re: [MarkLogic Dev General] How To Get The "Content" of An Index?

Geert/Kelley & others,

How can I thank you?

It works! :-)

The explanations of what was going on were great (on the document order 
explanation from Kelly and the document order vs sequence order from Geert with 
the syntax) and of course the solution that works.

Note: Do others feel the syntax is heavy?? Ugh! :'(  , :-)

 It was a good learning experience but without your help I wonder if I would 
have ever pulled out the content.

I was just introduced to this forum on Monday and it is already paying off. 
Probably will hear more from me.

Maybe I can also assist someone some day!

Thanks again,
Randy

On 5/11/2011 12:22 PM, Geert Josten wrote:

Just to add to the excelent example:

What you need to make the $song-doc//ts:Value[position() = ($x + 1)] work is 
ensure the predicate is not applied to document order, but to sequence order. 
You need to convert the part before the predicate to a sequence, which is very 
easily done by wrapping it in braces:

($song-doc//ts:Value)[position() =($x + 1)]

Overlooked that bit previous time, sorry.. ;)

Kind regards,
Geert

-----Oorspronkelijk bericht-----
Van: 
[email protected]<mailto:[email protected]>
 [mailto:[email protected]] Namens Kelly Stirman
Verzonden: woensdag 11 mei 2011 19:05
Aan: [email protected]<mailto:[email protected]>
Onderwerp: Re: [MarkLogic Dev General] How To Get The "Content" of An Index?

Hi Randy,

Index-of will return you the position of an item in a sequence.

Your position predicate, on the other hand, refers to the position with respect 
to document order. So, considering the following:

let $doc :=
  <doc>
   <foo>
    <value>cat</value>
    <value>dog</value>
   </foo>
   <bar>
    <value>cat</value>
    <value>dog</value>
   </bar>
  </doc>
  return
  xdmp:path($doc//value)
-->
/doc/foo/value[1]
/doc/foo/value[2]
/doc/bar/value[1]
/doc/bar/value[2]

That hopefully clears up why your code wasn't doing what you were hoping it 
would do.

You could filter for only the 5 values you want by doing something like:

for $match in 
$song-doc//ts:Value[cts:contains(.,("cat","dog","mouse","aye-aye","elephant"))]
return <div class="abc">Interesting Match: {$match/text()}</div>

Any closer?

Kelly

Message: 2
Date: Wed, 11 May 2011 11:41:11 -0500
From: Randy Smith <[email protected]><mailto:[email protected]>
Subject: Re: [MarkLogic Dev General] How To Get The "Content" of An
        Index?
To: General MarkLogic Developer Discussion
        
<[email protected]><mailto:[email protected]>
Message-ID: 
<[email protected]><mailto:[email protected]>
Content-Type: text/plain; charset="iso-8859-1"

Geert & Others,
Thanks for the input!
I thought maybe you had given me the solution but still having problems.

*The situation is like this:*
1. I'm new to these murky waters. :-)
2. I'm thinking this is generally a straight forward problem except for the 
following wrinkle that I was trying to solve without a serious code
rewrite:
3. I have ~20,000 documents where almost all have unique element names that are 
great for faceting like e.g. "ResponsibleParty", "Date", etc...
I set up my range indexes for them and things work great.
     However, one of the elements I'm interested in i.e. "Value" can appear up 
to ~1500+ times in a single document and have *_different _*content *_each 
time_*.  Turns out I am only interested in about 5 possible content (character 
strings) that appear in the element "Value".

4. I use:
*{if { fn:contains(fn:string-join(($song-doc//ts:Value), ""   , "", "Cat"))
then /<div class="abc"> Value Cat: {
/fn:string-join(($song-doc//ts:Value), ""   , ""/</div>/**
else()}*


to determine if "cat" is present in any of the 1500 content values and if it 
is, display them. *This works great except it outputs _all_of them to the 
browser*. ??

I can also find the position in "Value" were "cat" is found using

{if {$song-doc//ts:Value[.= 'Cat'])
then let $x := fn:index-of ($song-doc//ts:Value, 'Cat')

But when I us the index (i.e. $x) and add this:

/return/

/{<div class="abc"> Content of "Value" at "cat" + 1  =
{//$song-doc//ts:Value[position() =($x + 1)]}</div>/}


this does not work. It returns nothing.
I found out today when trying different things that if I put the integer
"1" in place of ($x+1) it, again, returns ALL of the "Value" strings.
However, anything other than "1" returns nothing. ???? Not sure why.


5. You can see I'm dancing around the solution but it still escapes me. :-)6. 
Maybe you can't get there from here, but I seems close.
7. The suggestion to create an "document" just for the content of
"Value" sounds good, but I do not know how to proceed to do that given
my newness.
8. I also thought about filtering the "Value" element in the xml data as
it comes in but we would like ALL of the data to be present for data mining.
9. I think I need council in the form of a teacher! :-)




Again, thanks for the help,
Randy
_______________________________________________
General mailing list
[email protected]<mailto:[email protected]>http://developer.marklogic.com/mailman/listinfo/general
_______________________________________________
General mailing list
[email protected]<mailto:[email protected]>http://developer.marklogic.com/mailman/listinfo/general
_______________________________________________
General mailing list
[email protected]
http://developer.marklogic.com/mailman/listinfo/general

Reply via email to