kosnkov
kosnkov

Reputation: 5941

Xpath xlst text function in brackets

having this xml

<?xml version="1.0" encoding="UTF-8"?>

<bookstore>

<book>
  <title lang="en">Harry Potter</title>
  <price>29.99</price>
</book>

<book>
  <title lang="en">Learning XML</title>
  <price>39.95</price>
</book>

</bookstore>

how to understand

count(bookstore/book[text()]) > 1 ?

Upvotes: 0

Views: 759

Answers (4)

Michael Kay
Michael Kay

Reputation: 163458

book[text()] matches a book element if it has a child text node. That part is easy.

Now your examples, like:

<book>
  <title lang="en">Harry Potter</title>
  <price>29.99</price>
</book>

Does the book element have a child text node here? Well, it depends. It certainly has two element node children, but they don't count. It MAY also have three whitespace-only text nodes - the whitespace between <book> and <title, between </title> and <price, and the whitespace between </price> and </book.

In general, if you don't have an <xsl:strip-space> declaration in your stylesheet, then these text nodes exist. However, they may be removed under a number of circumstances:

(a) The Microsoft MSXML parser notoriously removes whitespace unless you politely ask it not to. (And if you're running in the browser, there is no way of asking).

(b) If you have a DTD or schema that defines <book> as having element-only content, and if you validate against the DTD or schema, then XSLT 2.0 says the whitespace should be stripped.

(c) You may be building the input tree yourself, e.g. as a DOM, or you might be building the tree using other external tools, and they may have options to remove whitespace.

Upvotes: 1

Rudramuni TP
Rudramuni TP

Reputation: 1278

I assume xpath should be like this, if you are checking for '<book>' with immediate text, where XML elements are having indentations and line breaks.

count(bookstore/book[text()[normalize-space()]]) gt 0

count(bookstore/book[text()]) > 1 will give result 'true' as <book> is having space after it, which is also text.

Sample XML:

<bookstore>
<book>
  <title lang="en">Harry Potter</title>
  <price>29.99</price>
</book>

<book>2
  <title lang="en">Learning XML</title>
  <price>39.95</price>
</book>
<book>7</book>
</bookstore>

XSLT:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>

<xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
</xsl:template>

<xsl:template match="/">
    <xsl:if test="count(bookstore/book[text()[normalize-space()]]) gt 0">
        <xsl:value-of select="count(bookstore/book[text()[normalize-space()]])"/>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

Will give the result 2 as there are three <book> elements are there, but second and third <book> elements are having immediate text (those text are 2 and 7), but first one is having one element (not the immediate text).

If your input xml supplied to this XSLT then there will be count=0, because <book> is not having immediate text (spaces are not consider, because I used normalize-space() function).

Upvotes: 1

Joel M. Lamsen
Joel M. Lamsen

Reputation: 7173

Your xpath expression (which counts books that have a child text node) evaluates to true if it is greater than 1; false if not.

Upvotes: 1

michael.hor257k
michael.hor257k

Reputation: 117073

The expression in square brackets is a predicate.

Your expression counts (only) books that have a child text node.

Upvotes: 1

Related Questions