[Lxml-checkins] r44621 - lxml/branch/html/src/lxml/html/tests

ianb at codespeak.net ianb at codespeak.net
Fri Jun 29 18:51:58 CEST 2007


Author: ianb
Date: Fri Jun 29 18:51:58 2007
New Revision: 44621

Added:
   lxml/branch/html/src/lxml/html/tests/css_shakespear.html   (contents, props changed)
   lxml/branch/html/src/lxml/html/tests/test_css.py   (contents, props changed)
   lxml/branch/html/src/lxml/html/tests/test_css.txt   (contents, props changed)
Log:
Added incomplete CSS selector code

Added: lxml/branch/html/src/lxml/html/tests/css_shakespear.html
==============================================================================
--- (empty file)
+++ lxml/branch/html/src/lxml/html/tests/css_shakespear.html	Fri Jun 29 18:51:58 2007
@@ -0,0 +1,526 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" debug="true">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+</head>
+
+<body>
+	
+	<div id="test">
+	<div class="dialog">
+	<h2>As You Like It</h2>
+	<div id="playwright">
+
+	  by William Shakespeare
+
+
+	</div>
+	<div class="dialog scene thirdClass" id="scene1">
+
+	  <h3>ACT I, SCENE III. A room in the palace.</h3>
+
+	  <div class="dialog">
+	  <div class="direction">Enter CELIA and ROSALIND</div>
+
+	  </div>
+
+	  <div id="speech1" class="character">CELIA</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.1">Why, cousin! why, Rosalind! Cupid have mercy! not a word?</div>
+
+	  </div>
+
+	  <div id="speech2" class="character">ROSALIND</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.2">Not one to throw at a dog.</div>
+
+	  </div>
+
+	  <div id="speech3" class="character">CELIA</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.3">No, thy words are too precious to be cast away upon</div>
+
+	  <div id="scene1.3.4">curs; throw some of them at me; come, lame me with reasons.</div>
+
+	  </div>
+
+	  <div id="speech4" class="character">ROSALIND</div>
+
+	  <div id="speech5" class="character">CELIA</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.8">But is all this for your father?</div>
+
+	  </div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.5">Then there were two cousins laid up; when the one</div>
+	  <div id="scene1.3.6">should be lamed with reasons and the other mad</div>
+
+	  <div id="scene1.3.7">without any.</div>
+	  </div>
+
+	  <div id="speech6" class="character">ROSALIND</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.9">No, some of it is for my child's father. O, how</div>
+
+	  <div id="scene1.3.10">full of briers is this working-day world!</div>
+
+	  </div>
+
+	  <div id="speech7" class="character">CELIA</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.11">They are but burs, cousin, thrown upon thee in</div>
+	  <div id="scene1.3.12">holiday foolery: if we walk not in the trodden</div>
+
+	  <div id="scene1.3.13">paths our very petticoats will catch them.</div>
+
+	  </div>
+
+	  <div id="speech8" class="character">ROSALIND</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.14">I could shake them off my coat: these burs are in my heart.</div>
+	  </div>
+
+	  <div id="speech9" class="character">CELIA</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.15">Hem them away.</div>
+
+	  </div>
+
+	  <div id="speech10" class="character">ROSALIND</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.16">I would try, if I could cry 'hem' and have him.</div>
+	  </div>
+
+	  <div id="speech11" class="character">CELIA</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.17">Come, come, wrestle with thy affections.</div>
+
+	  </div>
+
+	  <div id="speech12" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.18">O, they take the part of a better wrestler than myself!</div>
+
+	  </div>
+
+	  <div id="speech13" class="character">CELIA</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.19">O, a good wish upon you! you will try in time, in</div>
+	  <div id="scene1.3.20">despite of a fall. But, turning these jests out of</div>
+	  <div id="scene1.3.21">service, let us talk in good earnest: is it</div>
+
+	  <div id="scene1.3.22">possible, on such a sudden, you should fall into so</div>
+
+	  <div id="scene1.3.23">strong a liking with old Sir Rowland's youngest son?</div>
+
+	  </div>
+
+	  <div id="speech14" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.24">The duke my father loved his father dearly.</div>
+
+	  </div>
+
+	  <div id="speech15" class="character">CELIA</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.25">Doth it therefore ensue that you should love his son</div>
+
+	  <div id="scene1.3.26">dearly? By this kind of chase, I should hate him,</div>
+
+	  <div id="scene1.3.27">for my father hated his father dearly; yet I hate</div>
+
+	  <div id="scene1.3.28">not Orlando.</div>
+
+	  </div>
+
+	  <div id="speech16" class="character">ROSALIND</div>
+
+	  <div title="wtf" class="dialog">
+
+	  <div id="scene1.3.29">No, faith, hate him not, for my sake.</div>
+
+	  </div>
+
+	  <div id="speech17" class="character">CELIA</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.30">Why should I not? doth he not deserve well?</div>
+
+	  </div>
+
+	  <div id="speech18" class="character">ROSALIND</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.31">Let me love him for that, and do you love him</div>
+	  <div id="scene1.3.32">because I do. Look, here comes the duke.</div>
+	  </div>
+
+	  <div id="speech19" class="character">CELIA</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.33">With his eyes full of anger.</div>
+	  <div class="direction">Enter DUKE FREDERICK, with Lords</div>
+	  </div>
+
+	  <div id="speech20" class="character">DUKE FREDERICK</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.34">Mistress, dispatch you with your safest haste</div>
+
+	  <div id="scene1.3.35">And get you from our court.</div>
+	  </div>
+
+	  <div id="speech21" class="character">ROSALIND</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.36">Me, uncle?</div>
+
+	  </div>
+
+	  <div id="speech22" class="character">DUKE FREDERICK</div>
+	  <div class="dialog">
+	  <div id="scene1.3.37">You, cousin</div>
+
+	  <div id="scene1.3.38">Within these ten days if that thou be'st found</div>
+
+	  <div id="scene1.3.39">So near our public court as twenty miles,</div>
+
+	  <div id="scene1.3.40">Thou diest for it.</div>
+
+	  </div>
+
+	  <div id="speech23" class="character">ROSALIND</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.41">                  I do beseech your grace,</div>
+
+	  <div id="scene1.3.42">Let me the knowledge of my fault bear with me:</div>
+	  <div id="scene1.3.43">If with myself I hold intelligence</div>
+
+	  <div id="scene1.3.44">Or have acquaintance with mine own desires,</div>
+
+	  <div id="scene1.3.45">If that I do not dream or be not frantic,--</div>
+
+	  <div id="scene1.3.46">As I do trust I am not--then, dear uncle,</div>
+
+	  <div id="scene1.3.47">Never so much as in a thought unborn</div>
+
+	  <div id="scene1.3.48">Did I offend your highness.</div>
+
+	  </div>
+
+	  <div id="speech24" class="character">DUKE FREDERICK</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.49">Thus do all traitors:</div>
+
+	  <div id="scene1.3.50">If their purgation did consist in words,</div>
+
+	  <div id="scene1.3.51">They are as innocent as grace itself:</div>
+
+	  <div id="scene1.3.52">Let it suffice thee that I trust thee not.</div>
+
+	  </div>
+
+	  <div id="speech25" class="character">ROSALIND</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.53">Yet your mistrust cannot make me a traitor:</div>
+
+	  <div id="scene1.3.54">Tell me whereon the likelihood depends.</div>
+
+	  </div>
+
+	  <div id="speech26" class="character">DUKE FREDERICK</div>
+	  <div class="dialog">
+
+	  <div id="scene1.3.55">Thou art thy father's daughter; there's enough.</div>
+
+	  </div>
+
+	  <div id="speech27" class="character">ROSALIND</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.56">So was I when your highness took his dukedom;</div>
+	  <div id="scene1.3.57">So was I when your highness banish'd him:</div>
+
+	  <div id="scene1.3.58">Treason is not inherited, my lord;</div>
+
+	  <div id="scene1.3.59">Or, if we did derive it from our friends,</div>
+
+	  <div id="scene1.3.60">What's that to me? my father was no traitor:</div>
+
+	  <div id="scene1.3.61">Then, good my liege, mistake me not so much</div>
+	  <div id="scene1.3.62">To think my poverty is treacherous.</div>
+
+	  </div>
+
+	  <div id="speech28" class="character">CELIA</div>
+	  <div class="dialog">
+
+	  <div id="scene1.3.63">Dear sovereign, hear me speak.</div>
+
+	  </div>
+
+	  <div id="speech29" class="character">DUKE FREDERICK</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.64">Ay, Celia; we stay'd her for your sake,</div>
+	  <div id="scene1.3.65">Else had she with her father ranged along.</div>
+
+	  </div>
+
+	  <div id="speech30" class="character">CELIA</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.66">I did not then entreat to have her stay;</div>
+	  <div id="scene1.3.67">It was your pleasure and your own remorse:</div>
+	  <div id="scene1.3.68">I was too young that time to value her;</div>
+
+	  <div id="scene1.3.69">But now I know her: if she be a traitor,</div>
+
+	  <div id="scene1.3.70">Why so am I; we still have slept together,</div>
+
+	  <div id="scene1.3.71">Rose at an instant, learn'd, play'd, eat together,</div>
+	  <div id="scene1.3.72">And wheresoever we went, like Juno's swans,</div>
+
+	  <div id="scene1.3.73">Still we went coupled and inseparable.</div>
+	  </div>
+
+	  <div id="speech31" class="character">DUKE FREDERICK</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.74">She is too subtle for thee; and her smoothness,</div>
+	  <div id="scene1.3.75">Her very silence and her patience</div>
+	  <div id="scene1.3.76">Speak to the people, and they pity her.</div>
+	  <div id="scene1.3.77">Thou art a fool: she robs thee of thy name;</div>
+
+	  <div id="scene1.3.78">And thou wilt show more bright and seem more virtuous</div>
+
+	  <div id="scene1.3.79">When she is gone. Then open not thy lips:</div>
+	  <div id="scene1.3.80">Firm and irrevocable is my doom</div>
+	  <div id="scene1.3.81">Which I have pass'd upon her; she is banish'd.</div>
+	  </div>
+
+	  <div id="speech32" class="character">CELIA</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.82">Pronounce that sentence then on me, my liege:</div>
+	  <div id="scene1.3.83">I cannot live out of her company.</div>
+	  </div>
+
+	  <div id="speech33" class="character">DUKE FREDERICK</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.84">You are a fool. You, niece, provide yourself:</div>
+
+	  <div id="scene1.3.85">If you outstay the time, upon mine honour,</div>
+	  <div id="scene1.3.86">And in the greatness of my word, you die.</div>
+	  <div class="direction">Exeunt DUKE FREDERICK and Lords</div>
+	  </div>
+
+	  <div id="speech34" class="character">CELIA</div>
+	  <div class="dialog">
+
+	  <div id="scene1.3.87">O my poor Rosalind, whither wilt thou go?</div>
+
+	  <div id="scene1.3.88">Wilt thou change fathers? I will give thee mine.</div>
+	  <div id="scene1.3.89">I charge thee, be not thou more grieved than I am.</div>
+
+	  </div>
+
+	  <div id="speech35" class="character">ROSALIND</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.90">I have more cause.</div>
+	  </div>
+
+	  <div id="speech36" class="character">CELIA</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.91">                  Thou hast not, cousin;</div>
+
+	  <div id="scene1.3.92">Prithee be cheerful: know'st thou not, the duke</div>
+
+	  <div id="scene1.3.93">Hath banish'd me, his daughter?</div>
+
+	  </div>
+
+	  <div id="speech37" class="character">ROSALIND</div>
+	  <div class="dialog">
+	  <div id="scene1.3.94">That he hath not.</div>
+
+	  </div>
+
+	  <div id="speech38" class="character">CELIA</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.95">No, hath not? Rosalind lacks then the love</div>
+
+	  <div id="scene1.3.96">Which teacheth thee that thou and I am one:</div>
+	  <div id="scene1.3.97">Shall we be sunder'd? shall we part, sweet girl?</div>
+
+	  <div id="scene1.3.98">No: let my father seek another heir.</div>
+
+	  <div id="scene1.3.99">Therefore devise with me how we may fly,</div>
+
+	  <div id="scene1.3.100">Whither to go and what to bear with us;</div>
+	  <div id="scene1.3.101">And do not seek to take your change upon you,</div>
+	  <div id="scene1.3.102">To bear your griefs yourself and leave me out;</div>
+
+	  <div id="scene1.3.103">For, by this heaven, now at our sorrows pale,</div>
+
+	  <div id="scene1.3.104">Say what thou canst, I'll go along with thee.</div>
+
+	  </div>
+
+	  <div id="speech39" class="character">ROSALIND</div>
+	  <div class="dialog">
+
+	  <div id="scene1.3.105">Why, whither shall we go?</div>
+
+	  </div>
+
+	  <div id="speech40" class="character">CELIA</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.106">To seek my uncle in the forest of Arden.</div>
+	  </div>
+
+	  <div id="speech41" class="character">ROSALIND</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.107">Alas, what danger will it be to us,</div>
+
+	  <div id="scene1.3.108">Maids as we are, to travel forth so far!</div>
+	  <div id="scene1.3.109">Beauty provoketh thieves sooner than gold.</div>
+
+	  </div>
+
+	  <div id="speech42" class="character">CELIA</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.110">I'll put myself in poor and mean attire</div>
+
+	  <div id="scene1.3.111">And with a kind of umber smirch my face;</div>
+	  <div id="scene1.3.112">The like do you: so shall we pass along</div>
+
+	  <div id="scene1.3.113">And never stir assailants.</div>
+
+	  </div>
+
+	  <div id="speech43" class="character">ROSALIND</div>
+	  <div class="dialog">
+
+	  <div id="scene1.3.114">Were it not better,</div>
+
+	  <div id="scene1.3.115">Because that I am more than common tall,</div>
+
+	  <div id="scene1.3.116">That I did suit me all points like a man?</div>
+
+	  <div id="scene1.3.117">A gallant curtle-axe upon my thigh,</div>
+
+	  <div id="scene1.3.118">A boar-spear in my hand; and--in my heart</div>
+
+	  <div id="scene1.3.119">Lie there what hidden woman's fear there will--</div>
+
+	  <div id="scene1.3.120">We'll have a swashing and a martial outside,</div>
+
+	  <div id="scene1.3.121">As many other mannish cowards have</div>
+
+	  <div id="scene1.3.122">That do outface it with their semblances.</div>
+
+	  </div>
+
+	  <div id="speech44" class="character">CELIA</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.123">What shall I call thee when thou art a man?</div>
+	  </div>
+
+	  <div id="speech45" class="character">ROSALIND</div>
+
+	  <div class="dialog">
+	  <div id="scene1.3.124">I'll have no worse a name than Jove's own page;</div>
+
+	  <div id="scene1.3.125">And therefore look you call me Ganymede.</div>
+
+	  <div id="scene1.3.126">But what will you be call'd?</div>
+
+	  </div>
+
+	  <div id="speech46" class="character">CELIA</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.127">Something that hath a reference to my state</div>
+	  <div id="scene1.3.128">No longer Celia, but Aliena.</div>
+
+	  </div>
+
+	  <div id="speech47" class="character">ROSALIND</div>
+	  <div class="dialog">
+
+	  <div id="scene1.3.129">But, cousin, what if we assay'd to steal</div>
+
+	  <div id="scene1.3.130">The clownish fool out of your father's court?</div>
+
+	  <div id="scene1.3.131">Would he not be a comfort to our travel?</div>
+
+	  </div>
+
+	  <div id="speech48" class="character">CELIA</div>
+
+	  <div class="dialog">
+
+	  <div id="scene1.3.132">He'll go along o'er the wide world with me;</div>
+
+	  <div id="scene1.3.133">Leave me alone to woo him. Let's away,</div>
+	  <div id="scene1.3.134">And get our jewels and our wealth together,</div>
+
+	  <div id="scene1.3.135">Devise the fittest time and safest way</div>
+
+	  <div id="scene1.3.136">To hide us from pursuit that will be made</div>
+
+	  <div id="scene1.3.137">After my flight. Now go we in content</div>
+
+	  <div id="scene1.3.138">To liberty and not to banishment.</div>
+	  <div class="direction">Exeunt</div>
+
+	  </div>
+
+	</div>
+	</div>
+</div>
+</body>
+
+</html>
\ No newline at end of file

Added: lxml/branch/html/src/lxml/html/tests/test_css.py
==============================================================================
--- (empty file)
+++ lxml/branch/html/src/lxml/html/tests/test_css.py	Fri Jun 29 18:51:58 2007
@@ -0,0 +1,112 @@
+import unittest
+from lxml.tests.common_imports import doctest
+from lxml import html
+from lxml.html import css
+import os
+
+doc_fn = os.path.join(os.path.dirname(__file__),
+                      'css_shakespear.html')
+
+# Data borrowed from http://mootools.net/slickspeed/
+
+class CSSTestCase(unittest.TestCase):
+    
+    selectors = [
+        ('*', 252),
+        ('div:only-child', 22), # ?
+        ('div:contains(CELIA)', 243),
+        ('div:nth-child(even)', 106),
+        ('div:nth-child(2n)', 106),
+        ('div:nth-child(odd)', 137),
+        ('div:nth-child(2n+1)', 137),
+        ('div:nth-child(n)', 243),
+        ('div:last-child', 53),
+        ('div:first-child', 51),
+        ('div > div', 242),
+        ('div + div', 190),
+        ('div ~ div', 190),
+        ('body', 1),
+        ('body div', 243),
+        ('div', 243),
+        ('div div', 242),
+        ('div div div', 241),
+        ('div, div, div', 243),
+        ('div, a, span', 243),
+        ('.dialog', 51),
+        ('div.dialog', 51),
+        ('div .dialog', 51),
+        ('div.character, div.dialog', 99),
+        ('#speech5', 1),
+        ('div#speech5', 1),
+        ('div #speech5', 1),
+        ('div.scene div.dialog', 49),
+        ('div#scene1 div.dialog div', 142),
+        ('#scene1 #speech1', 1),
+        ('div[class]', 103),
+        ('div[class=dialog]', 50),
+        ('div[class^=dia]', 51),
+        ('div[class$=log]', 50),
+        ('div[class*=sce]', 1),
+        ('div[class|=dialog]', 50), # ? Seems right
+        ('div[class!=madeup]', 243), # ? Seems right
+        ('div[class~=dialog]', 51), # ? Seems right
+        ]
+
+    def __init__(self, index):
+        self.index = index
+        unittest.TestCase.__init__(self)
+
+    @classmethod
+    def all(cls):
+        for i in range(len(cls.selectors)):
+            yield cls(i)
+
+    def runTest(self):
+        f = open(doc_fn, 'rb')
+        c = f.read()
+        f.close()
+        doc = html.HTML(c)
+        body = doc.xpath('//body')[0]
+        bad = []
+        selector, count = self.selectors[self.index]
+        xpath = css.xpath(css.parse(selector))
+        try:
+            results = body.xpath(xpath)
+        except Exception, e:
+            e.args = ("%s for xpath %r" % (e, xpath))
+            raise
+        found = {}
+        for item in results:
+            if item in found:
+                assert 0, (
+                    "Element shows up multiple times: %r" % item)
+            found[item] = None
+        if isinstance(results, basestring):
+            assert 0, (
+                "Got string result (%r), not element, for xpath %r"
+                % (results[:20], str(xpath)))
+        if len(results) != count:
+            #if self.shortDescription() == 'div.character, div.dialog':
+            #    import pdb; pdb.set_trace()
+            assert 0, (
+                "Did not get expected results (%s) instead %s for xpath %r"
+                % (count, len(results), str(xpath)))
+
+    def shortDescription(self):
+        return self.selectors[self.index][0]
+
+def unique(s):
+    found = {}
+    result = []
+    for item in s:
+        if item in found:
+            continue
+        found[item] = None
+        result.append(s)
+    return result
+        
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTests([doctest.DocFileSuite('test_css.txt')])
+    suite.addTests(list(CSSTestCase.all()))
+    return suite

Added: lxml/branch/html/src/lxml/html/tests/test_css.txt
==============================================================================
--- (empty file)
+++ lxml/branch/html/src/lxml/html/tests/test_css.txt	Fri Jun 29 18:51:58 2007
@@ -0,0 +1,110 @@
+A quick test of tokenizing:
+
+    >>> from lxml.html.css import tokenize, parse
+    >>> def ptok(s):
+    ...     for item in tokenize(s):
+    ...         print repr(item)
+    >>> ptok('E > f[a~="y\\"x"]')
+    Symbol(u'E', 0)
+    Token(u'>', 2)
+    Symbol(u'f', 4)
+    Token(u'[', 5)
+    Symbol(u'a', 6)
+    Token(u'~=', 7)
+    String(u'y"x', 9)
+    Token(u']', 15)
+
+Then of parsing:
+
+    >>> parse('div, td.foo, div.bar span')
+    Or([Element[div], Class[Element[td].foo], CombinedSelector[Class[Element[div].bar] <followed> Element[span]]])
+    >>> parse('div > p')
+    CombinedSelector[Element[div] > Element[p]]
+    >>> parse('td:first')
+    Pseudo[Element[td]:first]
+    >>> parse('a[name]')
+    Attrib[Element[a][name]]
+    >>> parse('a[rel="include"]')
+    Attrib[Element[a][rel = String(u'include', 6)]]
+    >>> parse('a[hreflang |= \'en\']')
+    Attrib[Element[a][hreflang |= String(u'en', 14)]]
+    >>> parse('div:nth-child(10)')
+    Function[Element[div]:nth-child(10)]
+    >>> parse('div:nth-of-type(10)')
+    Function[Element[div]:nth-of-type(10)]
+    >>> parse('label:only')
+    Pseudo[Element[label]:only]
+    >>> parse('a:lang(fr)')
+    Function[Element[a]:lang(Element[fr])]
+    >>> parse('div:contains("foo")')
+    Function[Element[div]:contains(String(u'foo', 13))]
+    >>> parse('div#foobar')
+    Hash[Element[div]#foobar]
+    >>> parse('div:not(div.foo)')
+    Function[Element[div]:not(Class[Element[div].foo])]
+    >>> parse('td ~ th')
+    CombinedSelector[Element[td] ~ Element[th]]
+
+Now of translation:
+
+    >>> def xpath(css):
+    ...     print parse(css).xpath()
+    >>> xpath('*')
+    *
+    >>> xpath('E')
+    e
+    >>> xpath('E[foo]')
+    e[@foo]
+    >>> xpath('E[foo="bar"]')
+    e[@foo = 'bar']
+    >>> xpath('E[foo~="bar"]')
+    e[contains(concat(' ', normalize-space(@foo), ' '), ' bar ')]
+    >>> xpath('E[foo^="bar"]')
+    e[starts-with(@foo, 'bar')]
+    >>> xpath('E[foo$="bar"]')
+    e[substring(@foo, string-length(@foo)-2) = 'bar']
+    >>> xpath('E[foo*="bar"]')
+    e[contains(@foo, 'bar')]
+    >>> xpath('E[hreflang|="en"]')
+    e[@hreflang = 'en' or starts-with(@hreflang, 'en-')]
+    >>> #xpath('E:root')
+    >>> xpath('E:nth-child(1)')
+    */e[0]
+    >>> xpath('E:nth-last-child(1)')
+    */e[last() - 0]
+    >>> xpath('E:nth-of-type(1)')
+    */e[0]
+    >>> xpath('E:nth-last-of-type(1)')
+    */e[last() - 0]
+    >>> xpath('E:first-child')
+    */e[position() = 0]
+    >>> xpath('E:last-child')
+    */e[position() = last()]
+    >>> xpath('E:first-of-type')
+    */e[0]
+    >>> xpath('E:last-of-type')
+    e[last()]
+    >>> xpath('E:only-child')
+    e[count(..) = 1]
+    >>> xpath('E:only-of-type')
+    e[count(../node-name(.)) = 1]
+    >>> xpath('E:empty')
+    e[count(.) = 0 and string(.) = '']
+    >>> xpath('E:contains("foo")')
+    e[contains(css:lower-case(string(.)), 'foo')]
+    >>> xpath('E.warning')
+    e[contains(concat(' ', normalize-space(@class), ' '), ' warning ')]
+    >>> xpath('E#myid')
+    e[@id='myid']
+    >>> xpath('E:not(:contains("foo"))')
+    e[not(contains(css:lower-case(string(.)), 'foo'))]
+    >>> xpath('E F')
+    e/descendant::f
+    >>> xpath('E > F')
+    e/f
+    >>> xpath('E + F')
+    e/following-sibling::f[0]
+    >>> xpath('E ~ F')
+    e/following-sibling::f
+    >>> xpath('div#container p')
+    div[@id='container']/descendant::p


More information about the lxml-checkins mailing list