<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel>
    <title>Select HTML elements with more than one css class using XPath</title>
    <link>http://westhoffswelt.de/blog/0036_xpath_to_select_html_by_class.html</link>
    <description>Using XPath it is easily possible to select all HTML nodes with a certain class argument. If you want to take into account nodes, which provide multiple classes the expression might not be intuitive. This article presents two XPath expressions for this purpose. One of them is compatible with XPath 1.0, while the other one uses new features only available in XPath 2.0.
</description>
    <language>en</language>
    <copyright>CC by-nc-sa</copyright>
    <managingEditor>Jakob Westhoff</managingEditor>
    <managingEditor>Jakob Westhoff &lt;jakob@westhoffswelt.de&gt;</managingEditor>
    <pubDate>Mon, 08 Jun 2009 22:13:57 +0000</pubDate>
    <lastBuildDate>Mon, 08 Jun 2009 22:26:57 +0000</lastBuildDate>
    <generator>eZ Components Feed dev (http://ezcomponents.org/docs/tutorials/Feed)</generator>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <item>
      <title>David Bruant at Tue, 03 Aug 2010 12:31:48 +0200</title>
      <link>http://westhoffswelt.de/blog/0036_xpath_to_select_html_by_class.html#comment_10</link>
      <description>Interesting post and comments.&#13;
Xpath 1.0 (still the only version supported in PHP) supports the start-with function (http://www.w3.org/TR/xpath/#function-starts-with) which can make your solution slightly more easily readable :&#13;
&#13;
//*[ &#13;
contains( normalize-space( @class ), ' $classname ' ) or&#13;
starts-with( normalize-space( @class ), '$classname ') or &#13;
substring( normalize-space( @class ), string-length( @class ) - string-length( '$classname' ) ) = ' $classname' or &#13;
@class = '$classname' ]&#13;
&#13;
Sadly, the ends-with function has only been added in XPath 2.0 (http://www.w3.org/TR/xquery-operators/#func-ends-with)&#13;
&#13;
Sam's solutions is very elegant, indeed.</description>
      <author>David Bruant</author>
      <pubDate>Tue, 03 Aug 2010 10:31:48 +0000</pubDate>
    </item>
    <item>
      <title>edwin at Thu, 18 Feb 2010 07:43:04 +0100</title>
      <link>http://westhoffswelt.de/blog/0036_xpath_to_select_html_by_class.html#comment_9</link>
      <description>Nice post.</description>
      <author>edwin</author>
      <pubDate>Thu, 18 Feb 2010 06:43:04 +0000</pubDate>
    </item>
    <item>
      <title>Jakob at Sun, 13 Dec 2009 16:05:54 +0100</title>
      <link>http://westhoffswelt.de/blog/0036_xpath_to_select_html_by_class.html#comment_8</link>
      <description>@luka8088: &#13;
I am glad I could help. &#13;
"normalize-space" ensures every space/tab combination inbetween to classes is reduced to one simple space. This way it is ensured that the matching does work even if there are multiple spaces or tabs between the different classes.&#13;
&#13;
greetings,&#13;
Jakob</description>
      <author>Jakob</author>
      <pubDate>Sun, 13 Dec 2009 15:05:54 +0000</pubDate>
    </item>
    <item>
      <title>luka8088 at Sun, 13 Dec 2009 11:01:28 +0100</title>
      <link>http://westhoffswelt.de/blog/0036_xpath_to_select_html_by_class.html#comment_7</link>
      <description>Hi, thanks for posting this, it was very helpful !&#13;
&#13;
I was hoping to find something like |= in css3, but this is also a elegant solution :)&#13;
&#13;
I just don't understand what is the purpose of normalize-space ? It will work the same without it ... Or it is faster that way ? Also, checking that element has a class attribute ? Is it for optimization or ?&#13;
&#13;
Anyway, good job and thanks :)&#13;
&#13;
</description>
      <author>luka8088</author>
      <pubDate>Sun, 13 Dec 2009 10:01:28 +0000</pubDate>
    </item>
    <item>
      <title>Nitin at Fri, 02 Oct 2009 23:31:47 +0200</title>
      <link>http://westhoffswelt.de/blog/0036_xpath_to_select_html_by_class.html#comment_6</link>
      <description>Just wanted to drop my regards to you, it helped me in one of my recent project. &#13;
&#13;
Thanks Jacob and Sam.</description>
      <author>Nitin</author>
      <pubDate>Fri, 02 Oct 2009 21:31:47 +0000</pubDate>
    </item>
    <item>
      <title>Jakob at Tue, 09 Jun 2009 17:25:43 +0200</title>
      <link>http://westhoffswelt.de/blog/0036_xpath_to_select_html_by_class.html#comment_5</link>
      <description>@Jan!:&#13;
&#13;
Yeah you are right. I have been in a hurry and overlooked the spaces around $classname. I thought he was proposing to search for '$classname' (without the spaces).&#13;
&#13;
@Sam:&#13;
&#13;
I am sorry about misreading your expression first. What you proposed should work without a problem. And is a really elegant solution :) Thanks for your input&#13;
&#13;
greetings&#13;
Jakob</description>
      <author>Jakob</author>
      <pubDate>Tue, 09 Jun 2009 15:25:43 +0000</pubDate>
    </item>
    <item>
      <title>Jan! at Tue, 09 Jun 2009 15:50:56 +0200</title>
      <link>http://westhoffswelt.de/blog/0036_xpath_to_select_html_by_class.html#comment_4</link>
      <description>@Jakob: how exactly would Sam's method fail on that example? It would be searching for " bar " in " foobar ".</description>
      <author>Jan!</author>
      <pubDate>Tue, 09 Jun 2009 13:50:56 +0000</pubDate>
    </item>
    <item>
      <title>Jakob at Tue, 09 Jun 2009 13:42:54 +0200</title>
      <link>http://westhoffswelt.de/blog/0036_xpath_to_select_html_by_class.html#comment_3</link>
      <description>@Sam:&#13;
&#13;
The problem with this approach is that parts of classes would be matched, too. &#13;
For example if &lt;div class="foobar"&gt; is given it would match the class "bar" or "foo", which is not the intended behaviour.&#13;
&#13;
@Ruben:&#13;
&#13;
You are right about libxslt supporting exslt, which enables us to use these functions in XSLTs. Unfortunately I needed an expression to simple Match DOM nodes inside of PHP. I didn't want to write an XSLT for it, apply it to the source document and read the result in. This seems to be a lot of unneeded hassle ;).&#13;
&#13;
Anyway thanks for the information about the node sets in conjunction with equal checks. This makes the XPath 2.0 expression even more elegant.&#13;
&#13;
greetings&#13;
Jakob</description>
      <author>Jakob</author>
      <pubDate>Tue, 09 Jun 2009 11:42:54 +0000</pubDate>
    </item>
    <item>
      <title>Ruben Wagner at Tue, 09 Jun 2009 11:19:58 +0200</title>
      <link>http://westhoffswelt.de/blog/0036_xpath_to_select_html_by_class.html#comment_2</link>
      <description>PHP (libxslt) supports exslt (http://www.exslt.org) so you can use&#13;
&#13;
//div['foo' = str:tokenize(@class)]&#13;
&#13;
if you define the namespace "str" in your stylesheet: xmlns:str="http://exslt.org/strings"&#13;
&#13;
&lt;xsl:stylesheet&#13;
  version="1.0"&#13;
  xmlns:str="http://exslt.org/strings"&#13;
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&#13;
&gt;&#13;
  &lt;!-- ... --&gt;&#13;
&lt;/xsl:stylesheet&gt;&#13;
&#13;
P.S. When you compare a string with a node set it returns true, if any node's value equals the string.&#13;
</description>
      <author>Ruben Wagner</author>
      <pubDate>Tue, 09 Jun 2009 09:19:58 +0000</pubDate>
    </item>
    <item>
      <title>Sam Shull at Tue, 09 Jun 2009 04:14:35 +0200</title>
      <link>http://westhoffswelt.de/blog/0036_xpath_to_select_html_by_class.html#comment_1</link>
      <description>How about:&#13;
&#13;
//*[&#13;
    @class and &#13;
    contains(&#13;
        concat(&#13;
            ' ',&#13;
            normalize-space(@class),&#13;
            ' '&#13;
        ),&#13;
        ' $classname '&#13;
    )&#13;
]</description>
      <author>Sam Shull</author>
      <pubDate>Tue, 09 Jun 2009 02:14:35 +0000</pubDate>
    </item>
  </channel>
</rss>

