From 206f7af3c4edff3bdac98ec6f29596b013b61032 Mon Sep 17 00:00:00 2001
From: Wouter Scherphof
Date: Tue, 26 Mar 2013 09:57:00 +0100
Subject: [PATCH] closes #6
:not(), [att=val], [att!=val], [att|=val], [att*=val], [att~=val],
[att^=val], [att$=val]
Note that the selection is now returned as a simple Set, breaking the
abilty brought in by #8 and #9 tot :select() or () on the selection. Of
course, the elements in the returned Set are still ElementNodes that
can be selected upon.
---
ElementNode.lua | 63 +++++++++++++++++++++++++++++++++----------------
test.html | 12 +++++-----
test.lua | 11 +++++++++
3 files changed, 60 insertions(+), 26 deletions(-)
diff --git a/ElementNode.lua b/ElementNode.lua
index 4b530ea..92c5789 100644
--- a/ElementNode.lua
+++ b/ElementNode.lua
@@ -87,33 +87,57 @@ function ElementNode:close(closestart, closeend)
end
end
+local function escape(s)
+ local replace = {
+ ["^"] = "%^", ["$"] = "%$", ["("] = "%(", [")"] = "%)", ["%"] = "%%", ["."] = "%.",
+ ["["] = "%[", ["]"] = "%]", ["*"] = "%*", ["+"] = "%+", ["-"] = "%-", ["?"] = "%?"
+ }
+ local res = ""
+ for c in string.gmatch(s, ".") do
+ res = res .. (replace[c] or c)
+ end
+ return res
+end
+
local function select(self, s)
if not s or type(s) ~= "string" or s == "" then return Set:new() end
-
+ local sets = {[""] = self.deeperelements, ["["] = self.deeperattributes,
+ ["#"] = self.deeperids, ["."] = self.deeperclasses}
local function match(t, w)
- local sets = {
- [""] = self.deeperelements,
- ["["] = self.deeperattributes,
- ["#"] = self.deeperids,
- ["."] = self.deeperclasses
- }
- local v
- if t == "[" then
- w, v = string.match(w,
- "([^=]+)" .. -- w = 1 or more characters up to a possible "="
- "=?" .. -- an optional uncaptured "="
- "(.*)" -- v = anything following the "=", or else ""
+ local m, v
+ if t == "[" then w, m, v = string.match(w,
+ "([^=|%*~%$!%^]+)" .. -- w = 1 or more characters up to a possible "=", "|", "*", "~", "$", "!", or "^"
+ "([|%*~%$!%^]?)" .. -- m = an optional "|", "*", "~", "$", "!", or "^", preceding the optional "="
+ "=?" .. -- an optional uncaptured "="
+ "(.*)" -- v = anything following the "=", or else ""
)
end
- local matched = sets[t][w]
+ local matched = Set:new(sets[t][w])
+ -- attribute value selectors
if v and v ~= "" then
v = string.sub(v, 2, #v - 1) -- strip quotes
for node in pairs(matched) do
- if node.attributes[w] ~= v then
- matched:remove(node)
+ local a = node.attributes[w]
+ -- equals
+ if m == "" and a ~= v then matched:remove(node)
+ -- not equals
+ elseif m == "!" and a == v then matched:remove(node)
+ -- prefix
+ elseif m =="|" and string.match(a, "^[^-]*") ~= v then matched:remove(node)
+ -- contains
+ elseif m =="*" and string.match(a, escape(v)) ~= v then matched:remove(node)
+ -- word
+ elseif m =="~" then matched:remove(node)
+ for word in string.gmatch(a, "%S+") do
+ if word == v then matched:add(node) break end
+ end
+ -- starts with
+ elseif m =="^" and string.match(a, "^" .. escape(v)) ~= v then matched:remove(node)
+ -- ends with
+ elseif m =="$" and string.match(a, escape(v) .. "$") ~= v then matched:remove(node)
end
- end
- end
+ end -- for node
+ end -- if v
return matched
end
@@ -123,8 +147,7 @@ local function select(self, s)
resultset = Set:new()
for subject in pairs(subjects) do
local star = subject.deepernodes
- if childrenonly then star = Set:new(subject.nodes) end
- childrenonly = false
+ if childrenonly then star = Set:new(subject.nodes) childrenonly = false end
resultset = resultset + star
end
if part == "*" then goto nextpart end
diff --git a/test.html b/test.html
index dbff550..5bf3d11 100644
--- a/test.html
+++ b/test.html
@@ -1,11 +1,11 @@
-
+
-
-
+
+
-
+