newtfire / digitProjectDesign-Hub

shared repo for DIGIT 400: Digital Project Design class at Penn State Erie, The Behrend College
Creative Commons Zero v1.0 Universal
12 stars 2 forks source link

XPath 4 Help #27

Closed elmusfi closed 3 years ago

elmusfi commented 3 years ago

Hi,

I'm currently working on number 3 of the fourth XPath homework and I have a question about parts b and c. So far for part a, I've gotten this:

//head/date[text()[contains(., 'F ')]]

but, I can't seem to get the next two parts. I've interpreted the questions as how to get the text of the when attributes in the date element only for Fridays, but anything I do seems to include all days, not just Fridays. Here is my latest attempt:

for $i in (//head/date[text()[contains(., 'F ')]]) return (string-join(//head/date/[@when], ', '))

With this, I'm trying to say that for all date elements containing a Friday, give me the value in the attribute when, but it's giving me every date, not just the Fridays. It is also giving me this list 15 times in a row, which I'm sure is due to how I have the for/return function written, but I'm not sure how to fix this either. Any help would be appreciated, thanks!

ebeshero commented 3 years ago

@elmusfi Wow! you're trying some very complex expressions here, and kudos for trying out the XPath for-loop. (That is a cool thing to try). The way your expression is working is to say, for each member of the sequence of results in those dates that contain "F", return a string-joined list of all the @when attributes. And because you used the for-loop, you're getting 15 different string-joined results, one for every Friday.

Okay, so you don't want that.

Let's walk this back. What happens when you just take your first expression, the one that returns the Fridays, and just step over to the attribute axis from there to collect the values of the @when attribute?

string-join() is already set up to work on a sequence of results, so it knows what to do when you send a sequence of 15 things to it. It bundles them up and applies a little separator to them. So try sending the results of your XPath expression ending in @when over to string-join() to bundle up for you. You don't really need to be treating each of those results separately, because this XPath function is like count() and distinct-values(): it'll take a sequence of things and do something to do them to, well, tie them up in a string.

Does that help?

elmusfi commented 3 years ago

Yes, I was able to get it to work without that for loop but I won't paste the exact answer here since this homework isn't due yet. I also ran into another issue with 4B. I've been able to get all of the values for the strings containing "GitHub" like you asked, but the min/max functions aren't working, they still only return all of the string lengths for the 17 different strings with "GitHub" in them.

Here's the expression without min/max:

//div[@type="assign"]//text()[contains(., 'GitHub')]/(string-length(.))

It returns 17 values: 450, 59, 41, etc.

Whenever I try to wrap min or max around the string-length function, it doesn't do anything. The results are the same. I've even tried putting them both together in [] like the assignment says to do, like this:

//div[@type="assign"]//text()[contains(., 'GitHub')]/[min((string-length(.))), max((string-length(.)))]

but it says there are no results. I'm just not sure how to format this. If I could get all of those string-length values into a list to throw into min() and max(), that would be ideal, but I'm not sure what my next step would be. Thanks for all your help!

ebeshero commented 3 years ago

@elmusfi I just tested your first expression to make sure there's not a syntax error. I returned 17 numbers, so string-length() is working there. Sometimes wrapping the functions around the whole expression can lead to syntax confusion--so many parentheses. So that's why I like the XPath 3.1 syntax using the arrow operator--it is just easier to read. Try just setting the arrow operator after your expression and sending it to max(). Then try it with min(). It worked over here for me.

When you see how that expression resolves, you can then try packing it into a predicate filter to say, find the text() node that answers "true" for having a string-length() = the min or max string-length().

ebeshero commented 3 years ago

So, we used the arrow operator in class, when, say, I was taking distinct values, like so:

//placeName() => distinct-values()

We could also do that with string-join() as well as count(), min() , and max().

//placeName => count()

Now, look at this expression:

//placeName ! string-length() => min()

That is first using the simple map ! operator to say, at each and every singe placeName node, return the string-length(). (If there are 17 placeName elements, I'll return 17 values). Then we use the arrow operator => to take all those results and send them for processing to the function that accepts a sequence: min() (or max() or count() etc.)