Using "And" , "Or" operators in Xquery - xquery

let us consider an example,
<li>
<div id="comments-list-245667" class="comments yui-u">
<h3><span class="fn n">Ram</span></h3>
</div>
<div id="comments-list-245687" class="comments yui-u">
<h3><span class="fn n"><a href='http://www.xyz.com' rel='external nofollow' class='url url'>laxman</a></span></h3>
</div>
</li>
Now how to get both "Ram" and "laxman" from the nodes using "and" or "or" operators.

Use:
/*/*/h3/(span[not(*)] | span/a)/string()
This produces a sequence of the string values of every span that doesn't have an element child or of every a that is child of a span and that (the span element is a child of an h3 element, that is a grand-child of the top element of the XML document.
BTW, the above happens also to be a pure XPath 2.0 expression (XPath 2.0 is a subset of XQuery).

Assuming capitalization isn't important (in XML you have "laxman", in your question "Laxman") and you want to get the <li>s (otherwise, "and" wouldn't be reasonable, but if you want, move some axis steps in/out the predicate). Each line is an alternative.
or:
/li[.//h3//*[lower-case(.) = ("ram", "laxman")]]
/li[.//h3//*[lower-case(.) = "ram"] or .//h3//*[lower-case(.) = "laxman"]]
and:
/li[.//h3//*[lower-case(.) = "ram"]][.//h3//*[lower-case(.) = "laxman"]]
/li[.//h3//*[lower-case(.) = "ram"] and .//h3//*[lower-case(.) = "laxman"]]
The first or-alternative exhibits XQuery operator's set semantics.

Related

:empty doesn't work if there's blank spaces?

Trying to find a pseudo class that'll target a <div> like this:
<div class="nav-previous">
</div>
I've tried :blank and :empty but neither can detect it. Is it just not possible to do?
https://jsfiddle.net/q3o1y74k/3/
:empty alone is enough.
By the current Selectors Level 4 specification, :empty can match elements that only contain text nodes that only contain whitespace as well as completely empty ones. It’s just there aren’t many that support it as per the current specification.
The :empty pseudo-class represents an element that has no children except, optionally, document white space characters.
From the MDN:
Note: In Selectors Level 4, the :empty pseudo-class was changed to act like :-moz-only-whitespace, but no browser currently supports this yet.
The :-moz-only-whitespace CSS pseudo-class matches elements that only contain text nodes that only contain whitespace. (This includes elements with empty text nodes and elements with no child nodes.)
As the others mentioned, this isn't possible with CSS yet.
You can check to see if there's only whitespace with JavaScript however. Here's a simple JS only solution, "empty" divs that match are blue, while divs that have text are red. Updated to add an empty class to the empty divs, which would allow you to target them easily with the selector .empty in your CSS.
The JS only "empty" comparison would look like this:
if(element.innerHTML.replace(/^\s*/, "").replace(/\s*$/, "") == "")
And if you're using jQuery it would be a bit easier:
if( $.trim( $(element).text() ) == "" ){
var navs = document.querySelectorAll(".nav-previous");
for( i=0; i < navs.length; i++ ){
if(navs[i].innerHTML.replace(/^\s*/, "").replace(/\s*$/, "") == "") {
navs[i].style.background = 'blue';
navs[i].classList.add( 'empty' );
} else {
navs[i].style.background = 'red';
}
}
.nav-previous {
padding: 10px;
border: 1px solid #000;
}
.nav-previous.empty {
border: 5px solid green;
}
<div class="nav-previous">
</div>
<div class="nav-previous">Not Empty </div>
The problem with your approach is that your container is not actually empty.
The :empty pseudo-class represents an element that has no children at
all. In terms of the document tree, only element nodes and content
nodes (such as DOM text nodes, CDATA nodes, and entity references)
whose data has a non-zero length must be considered as affecting
emptiness;
As you have empty spaces this pseudo class will not do the trick.
The :blank pseudo class should be the right one, because this is its definition:
This blank pseudo-class matches elements that only contain content
which consists of whitespace but are not empty.
the problem is that this pseudo class isn't implemented by any browser yet as you can check in the link below. So you will need to wait until it get implemented to be able to use this selector.
This pretty much explains the behavior you are facing
https://css4-selectors.com/selector/css4/blank-pseudo-class/
The best approach here is just to be sure that your div will actually be empty, so your approach will work.
the best that you can do is to define an empty class like this:
.empty{
display:none;
}
and then add this JS code here, it will append the empty class to your blank items:
(function($){
$.isBlank = function(html, obj){
return $.trim(html) === "" || obj.length == 0;
};
$('div').each(function() {
if($.isBlank(
$(this).html(),
$(this).contents().filter(function() {
return (this.nodeType !== Node.COMMENT_NODE);
})
)) {
$(this).addClass('empty');
}
});
})(jQuery);
check it working here,
https://jsfiddle.net/29eup5uw/
You just can't without JavaScript/jQuery implementation.
:empty selector works with empty tags (so without even any space in them) or with self-closing tags like <input />.
Reference: https://www.w3schools.com/cssref/css_selectors.asp
If you want to use JavaScript implementation, I guess here you will find the answer: How do I check if an HTML element is empty using jQuery?
:empty indeed only works for totally empty elements. Whitespace content means it is not empty, a single space or linebreak is already enough. Only HTML comments are considered to be 'no content'.
For more info see here: https://css-tricks.com/almanac/selectors/e/empty/
The :blank selector is in the works, it will match whitespace, see here: https://css-tricks.com/almanac/selectors/b/blank/. But it seems to have no browser support yet.
Update:
See here for possible solutions to this involving jQuery.

Xpath in Nightwatch.js

I have this structure
<div class ="wg-block">
...
<h4 class ="number" >
"Text"
I have to make sure that the element h4 with text "text" is in div.
I try this:
.useXpath()
.waitForElementVisible('/div[contains(#class, "wg-block")]/h4[text()="Text"]',1000)
but have an error.
How can I correctly be sure in visibility of this element?
Try to replace
'/div[contains(#class, "wg-block")]/h4[text()="Text"]'
with
'//div[#class = "wg-block"]//h4[normalize-space(text())="Text"]'
Note that starting / applicable for root element (which is html, but not div) and also / means direct child. So /div/h4 means h4 which is the direct child of a root element div.
You should use //div//h4 to match h4 which is descendant of div that is located somewhere in DOM
text()="Text" could be applied to match element <h4>Text</h4>,
but if you want to match
<h4>
Text
</h4>
you need to get rid of spaces and new line characters. In this case you can use normalize-space(text()) method or contains(text(), "Text")

XQuery loop conditions

I have a XML file that follows this DTD structure.
<!DOCTYPE report [
<!ELEMENT report (title,section+)>
<!ELEMENT section (title,body?,section*)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT body (para+)>
<!ELEMENT para(#PCDATA)>
<!ATTLIST book version CDATA #REQUIRED>
<!ATTLIST section number ID CDATA #REQUIRED>
]>
And I want to query the following two things using XQuery.
1. Get all titles that appear at least twice (two sections with same title).
for $x in /report/section/
for $y in /report/section/
where $x/#title = $y/#title
return $x/#title
2. Get the number and titles of all sections with at least 10 paragraphs in the body or 5 nested sections.
for $x in /report/section/
where $x/para >= 10 or count(/section) > 10
return <large>$x/number $x/title</large>
But my queries don't seem to be correct. I am a beginner with XQuery OR XPath, could someone tell me how to fix my queries?
Edit: Sample XML
<?xml version="1.0" encoding="UTF-8"?>
<report version = '1'>
<title>Harry Potter</title>
<section number = '1'>
<title>sec1</title>
<body>
<para>1</para>
<para>2</para>
<para>3</para>
<para>4</para>
<para>5</para>
<para>6</para>
<para>7</para>
<para>8</para>
<para>9</para>
<para>10</para>
<para>11</para>
</body>
</section>
<section number = '2'>
<title>sec2</title>
<body><para>test</para></body>
<section number = '2.1'>
<title>sec21</title>
<body>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
<para>test</para>
</body>
</section>
<section number = '2.2'>
<title>sec21</title>
<body><para>test</para></body>
</section>
<section number = '2.3'>
<title>sec23</title>
<body><para>test</para></body>
</section>
<section number = '2.4'>
<title>sec24</title>
<body><para>test</para></body>
</section>
<section number = '2.5'>
<title>sec25</title>
<body><para>test</para></body>
</section>
<section number = '2.6'>
<title>sec1</title>
<body><para>test</para></body>
</section>
</section>
</report>
In your first example, there are two problems. First off, you are not getting the nested sections, because you are only iterating over the section elements that are direct children of the report element. Secondly, you are using two loops over the same content. It is possible for both $x and $y to be the same element, so the where condition will match at least once for each section. I would write it like this:
for $x in distinct-values(/report//section/title)
where count(/report//section[title=$x]) > 1
return $x
The loop gets all unique titles and loops over them (note that we use report//section to get all descendant sections). Then for each of these, we count how many times it was used keeping the ones that occurred more than once. We then return the loop variable (which is bound to the title).
Running it, we get back
sec1 sec21
In the second case, we have the same problem of not getting all descendants. We also need to take the counts. I would use
for $x in /report//section
where count($x/body/para) > 9 or count($x/section) > 4
return <large>{$x/#number} {string($x/title)}</large>
Notice that I selected $x/body/para to get the paragraphs in the section (they occur as children of the body element). This counts the direct descendants, but can be modified to get all descendants if necessary. Notice also the use of curly brackets in the direct element constructor. When we construct a direct element, all text is read literally. The curly brackets are used to evaluate an xquery expression instead of literal text.
I used the string function on the title in order to extract the text contents of the element. If we didn't do that, we would get an actual title element instead of its content (which may be a desired behavior). As we extract the number attribute, it will be a attribute on our constructed element (if we wanted it to be text, we could have applied the string function to it).
In this case, it returns
<large number="1">sec1</large>
<large number="2">sec2</large>
<large number="2.1">sec21</large>
The examples here were tested using the OP's provided XML (example.xml) using Saxon-HE 9.7.0.2J. Only the relevant parts appear above, but the complete first example ran looks like
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method "text";
declare context item := doc("example.xml");
for $x in distinct-values(/report//section/title)
where count(/report//section[title=$x]) > 1
return $x
and the complete second example looks like
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method "xml";
declare context item := doc("example.xml");
for $x in /report//section
where count($x/body/para) > 9 or count($x/section) > 4
return <large>{$x/#number} {string($x/title)}</large>
For the first example in XQuery 3.0 I would use
declare context item := doc("example.xml");
for $x in /report//section/title/data()
group by $x
where count($x) > 1
return $x[1]

Nested elements naming style (Jade, HAML, Slim)

Looking for solution how to use SMACSS naming convention with jade, haml or slim template engine.
Expect following jade code :
.module
.child
.child
as output i'll get following:
<div class="module">
<div class="child"></div>
<div class="child"></div>
</div>
but i'd like to reach following result:
<div class="module">
<div class="module-child"></div>
<div class="module-child"></div>
</div>
is there any solution to manage it like i can do it in SASS for example, i mean avoid adding 'module-' string to each 'child' manually ?
UPDATE
Also acceptable solutions with Haml and Slim
This is the closest I got with jade (live playground here):
mixin e(elt)
- var a = attributes;
- var cl = attributes.class;delete attributes.class
- var elt = elt ? elt : 'div' // If no parameter given
if cl
- var cl = parent + '-' + cl
else
- var cl = parent
#{elt}&attributes({'class': cl}, attributes)
block
- var parent = 'box'
+e('aside')#so-special
+e('h2').title Related
+e('ul').list
+e('li').item: +e('a')(href='#').link Item 1
+e('li').item: +e('span').link.current Item 2 and current
+e('li').item#third(data-dash='fine', aria-live='polite') Item 3 not even a link
| multi-line
| block
// - var parent = 'other' problem of scope I guess
+e('li').item lorem ipsum dolor sit amet
- var parent = 'footer'
+e('footer')(role='contentInfo')
+e.inner © Company - 2014
A mixin named e will output an element taken as a parameter (default is div) with its attributes and content as is, except for the first class that'll be prefixed with the value of the variable parent (or will be the value of parent itself if it hasn't any class)
I prefer using default jade syntax for attributes, including class and id than passing many parameters to a mixin (this one doesn't need any if it's a div, as with .sth text'd output <div class="sth>text</div> and +e.sth text will output <div class="parent-sth>text</div>)
Mixin would be shorter if it didn't have to deal with other attributes (href, id, data-*, role, etc)
Remaining problem: changing the value of parent has no effect when it's indented. It had with simpler previous attempts so I guess it's related to scope of variables. You theoretically don't want to change the prefix for child elements but in practice... Maybe as a second optional parameter?
Things I had problem with while playing with jade:
attributes doesn't work as expected. Now it's &attributes(attributes). Thanks to jade-book issue on GitHub
but it'll output class untouched plus the prefixed one, so I had to remove it (delete) in a place it'd be executed by jade
Some thoughts from me: what's wrong with a variable?
- var myModule = 'module'
div(class="#{myModule}")
div(class="#{myModule}-child")
div(class="#{myModule}-child")
or combine it with an each:
- var myModule2 = 'foobar'
div(class="#{myModule2}")
each idx in [0, 1, 2, 3]
div(class="#{myModule2}-child") I'm child #{idx}
Sure, there is much more code to write, but if a change is neccessary then you must do this only at one point.
Ciao
Ralf
You should be able to achieve this with SASS. As long as you have the latest SASS version, you should be able to use the following syntax:
.module {
&-child {
}
}
Have a look at this article for more information on newer features of SASS http://davidwalsh.name/future-sass

Select element based on previous element of same type

I'm trying to select elements based on the class of a previous element of the same type.
For example, given the following HTML, select the third span element:
<div>
<span class="red"></span>
<span class="red"></span>
<p>
<span id="select me"></span>
</p>
<span id="don't select me"></span>
</div>
I want that span element to have the same properties as the previous span element because it has the class, "red."
Another way to say this: select an element with the class, "red," as well as the next element of the same type, regardless of class.
I'm having a tough time wrapping my head around this. Better than nothing would be a way to select the next sibling of the same type instead of just any following element. For example, span.red ~ span would be okay if it didn't mean "span element with ANY previous span sibling with a class red."
Thanks for any help.
Here are more examples:
<div>
<span class="red"></span>
<span id="select me"></span>
<p>
<span class="red"></span>
</p>
<span id="select me"></span>
</div>
In the example above, the second span element is chosen because the first span has a class, "red."
The last span element is chosen because the third span has a class, "red."
<div>
<span class="red"></span>
<span class="red"></span>
<p>
<b></b>
</p>
<span id="select me"></span>
</div>
The main reason for this is that I have elements in an editable div. They are numbered with a css counter. Some elements may be grouped together like a figure, i.e. 2a and 2b, while others are not, so I could end up with elements 1, 2a, 2b, 2c, 3, etc. The class name I use just tells me that it's a "sub" element and to increment the sub counter but not the main element counter. Not having a class for the next element after a bunch of sub elements tells me it's the last sub element and I should reset the sub counter. The reason I have it set up this way is because I want to be able to move around the elements and have the numbering update automatically. Also, it's easy to change whether something is a sub element just by toggling the class name.
I'd like to have another case or two to test this with, but this seems to work for your example:
span.red ~* span {
background: red;
}
jsFiddle example
There's no way to say "sibling of the same type" in a selector. But you can use the sibling selector following a selector of your choice, and combine these into a single selector that meets your needs, such as:
span.red + span, div.red + div
{
}
If it's only nested on level you could try this :
.red + * > span {
color: red;
}
What is the use case for this? Why not just add red to all elements you want to be styled the same way?

Resources