xmlxsltxpathxsl-fodita

Logical OR in XPath? Why isn't | (pipe symbol) working?


I've got an XSLT template which counts topics at all levels, for use in labeling those topics with numbering in DITA projects I've got.

<xsl:template match="*[contains(@class, ' bookmap/chapter ')] | *[contains(@class, ' map/topicref ')] [not(ancestor-or-self::*[contains(@class,' bookmap/frontmatter ')])]" mode="topicTitleNumber"> 
    <xsl:number format="1 " count="*[contains(@class, ' map/topicref ')] [not(ancestor-or-self::*[contains(@class,' bookmap/frontmatter ')])] | *[contains(@class, ' bookmap/chapter ')]" level="multiple"/> 
</xsl:template> 

I'm trying to add an additional exclusion to what gets counted though, for when a topicref class has a title element with an outputclass of noNum.

<xsl:template match="*[contains(@class, ' bookmap/chapter ')] | *[contains(@class, ' map/topicref ')] [not(ancestor-or-self::*[contains(@class,' bookmap/frontmatter ')])]" mode="topicTitleNumber"> 
    <xsl:number format="1 " count="*[contains(@class, ' map/topicref ')] [not(ancestor-or-self::*[contains(@class,' bookmap/frontmatter ')] | *[contains(title/@outputclass, 'noNum')])] | *[contains(@class, ' bookmap/chapter ')]" level="multiple"/> 
</xsl:template> 

Shown above, I added | *[contains(title/@outputclass, 'noNum')] after the first not statement, thinking that would function as an additional condition in which the count call would skip over when the template was called (i.e. ...not an ancestor-or-self with [criteria] or a topic with title outputclass attribute of 'noNum'...). However it appears that the criteria I added is treated as something the template does match on and count.

Assuming that I am correct on the last point, I believe I need to put that condition inside of its own 'not' statement, but I'm not sure how to do that with the conditions already present in the XPath.


Solution

  • In XPath | is a set union operator, not a logical OR.

    Union operator, |

    XPath 1.0

    The | operator computes the union of its operands, which must be node-sets.

    XPath 2.0+

    The union and | operators are equivalent. They take two node sequences as operands and return a sequence containing all the nodes that occur in either of the operands.


    Logical OR, or

    Use or instead for logical OR .


    Complex XPath still not working?

    Break it down to smaller parts:

    1. Does //*[contains(@class, ' bookmap/chapter ')] select what you expect? Repeat for each of the most basic parts of your logical expression individually.

    2. Combine those individually verified terms or predicates, one at a time, and observe that each step along the way, there are not surprises.

    3. Repair any discrepancies between expected and actual results before combining additional terms.