Selecting trailing empty nodes using xpath - xslt

How do I select trailing empty nodes? Empty, as in no text, that is.
In this example I want to ignore the first empty node, as it is not trailing, The last three nodes (under <bar>) have no text so I want to select them.
<foo>
<bar>
<node>blah blah</node>
<node></node> <-- Not this
<node>blah blah</node>
<node>blah blah</node>
<node></node> <-- But this
<node><node></node></node> <-- and this
</bar>
</foo>

If you use /foo/bar/node[not(normalize-space()) and not(following-sibling::node[normalize-space()])] you select the two node child elements that don't have any following sibling with text content. The second of those node elements contains a further node child, I am not sure whether you want to select that as well as part of the result.

Related

How do I test whether a text node intervenes between the current node and a defined preceding sibling?

In XPath/XSLT 2.0, how do I test whether a text node intervenes between the current node and a preceding sibling <lb/>, regardless whether non-text nodes intervene?
XML:
<lb/>I'd like to test whether this text exists.<someNode/><currentNode/>
Bonus question: what is the desired syntax if the <lb/> may be either a sibling of the current node or of the parent node?
<xsl:if test="preceding-sibling::text() >> preceding-sibling::lb"> tests whether there is a preceding sibling text node after a preceding sibling lb element: http://xsltransform.net/6pS1zCK.
In general (if there can be more than one element or text node) I think you need to use some $sib in preceding-sibling::lb satisfies some $text in preceding-sibling::text() satisfies $sib >> $text.

Meaning of this XPath expression

I am new to XML and XSLT programming.
Can anybody explain the meaning of below XPath expression?
<xsl:apply-templates select="//Order[Header/string-length(ORDERID) > 0]/Header/SAP_WBSELEMENT[not(. = following::SAP_WBSELEMENT)]" />
Meaning: Select SAP_WBSELEMENT elements, including those with duplicate string values only once, that are children of Header elements that are children of any Order elements in the document with a Header child with an ORDERID with an non-empty string value.
Breakdown: Working from the end of the XPath back to the front...
Select SAP_WBSELEMENT elements, excluding those with duplicate string values,
SAP_WBSELEMENT[not(. = following::SAP_WBSELEMENT)]
that are children of Header elements,
Header/
that are children of those Order elements with a Header child with an ORDERID with an non-empty string value,
Order[Header/string-length(ORDERID) > 0]/
anywhere in the document,
//

Regex - Match all subsections

I have the following strings which indicate a hierarchy:
JHW/1/24/3/562 // child row
JHW/1/24/3 // parent of the above
JHW/1/24 // parent of the above
JHW/1 // parent of the above
JHW // parent of the above
What I'd like to do is to be able to pull out all of the "parent" rows with one regex.
The closest I've got conceptually (which isn't anywhere near) is #^([^/]*/)+# which just matches the second-last section [eg. 3].
I've never really tried to do something like this before, where I'm trying to get overlapping results - it is possible? It's not an issue if it brings back the child row as one of the matches.
You can't obtain several results from the same position (since the regex engine go to the next character after each try of the pattern), you can explode the string with / and build each path you need with the array items.
An other possible way consists to reverse the string:
preg_match_all('~(?=(?:\A|/)(.+))~', strrev($path), $m);
$result = array_map('strrev', $m[1]);

XSL:Number count not working as expected -- Issue with my XPath?

Here's the XML
<row>
<cell>blah blah</cell>
<check>
<option/>
<option/>
<option/>
<option/>
<option/>
<option/>
</check>
</row>
Here is the XSL
<xsl:template match="row">
<xsl:variable name="inputLevel">
<xsl:number count="option" level="any" from="."/>
</xsl:variable>
<xsl:value-of select="$inputLevel"/>
</xsl:template>
All I get is "0". http://www.w3schools.com/XPath/xpath_syntax.asp says "." means the current node. Shouldn't it be returning "6"?
Edit1: I wanted to look for option tags at ANY level, not just check. Should have explained but the option tags could exist at any level below
If you want to count descendant options you shouldn't use xsl:number but:
<xsl:variable name="inputLevel" select="count(.//option)">
I think the problem is that the xpath expression option won't match anything at the row element - try this instead:
<xsl:number count="check/option" level="any" from="." />
To look for option elements at any level use the following syntax:
<xsl:number count="//option" level="any" from="." />
I don't think the from attribute is reqired, and the level attribute probably isn't doing what you think it is (I'm also not sure what it does...)
From the XSLT 1.0 W3C specification:
"If no value attribute is specified, then the xsl:number
element inserts a number based on the
position of the current node in the
source tree. The following
attributes control how the current
node is to be numbered:
The levelattribute specifies what
levels of the source tree should be
considered; it has the values
single, multiple or any. The
default is single.
The count attribute is a pattern
that specifies what nodes should be
counted at those levels. If count
attribute is not specified, then it
defaults to the pattern that matches
any node with the same node type as
the current node and, if the current
node has an expanded-name, with the
same expanded-name as the current node
When level="any", it constructs a
list of length one containing the
number of nodes that match the count
pattern and belong to the set
containing the current node and all
nodes at any level of the document
that are before the current node in
document order, excluding any
namespace and attribute nodes (in
other words the union of the members
of the preceding and ancestor-or-self
axes). If the from attribute is
specified, then only nodes after the
first node before the current node
that match the from pattern are
considered. ".
From this text it is clear that only nodes that are ancestors or are preceding the current node are counted.
In this question, the current node is the top element node row and it has 0 ancestor and 0 preceding element nodes.
Therefore, the returned result is correct!
Solution:
Use:
count(descendant::option)
The result of evaluating this expression is the count of all option elements in the document, that are descendents of the current node (the row element).

XPath, XSL: How to select all nodes, not just elements, when xsl:param is a node-set?

In an XSL recursion, this
<xsl:with-param name="items" select="$items[position() > 1]
would normally work to recurse with all nodes but the first. But it only works if the nodes are elements. If they are a mix of element and text nodes, the recursion fails, since, for example, $items[3] returns the third element node, not the third node, regardless whether text or element.
So the expression sets the new $items to just the element nodes in the old $items. The text nodes are lost.