# HG changeset patch
# User cmlenz
# Date 1157553590 0
# Node ID e4dad1145f84b822f1cc8a16d1ca58ab07ec93e9
# Parent 861105f3afe327302362e34c172f2dcae3005f61
Implement support for namespace prefixes in XPath expressions.
diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -32,6 +32,7 @@
matches the attributes of descendants.
* Fixes for `py:match` which would get confused when it should be applied
to multiple elements (ticket #49).
+ * Using namespace prefixes in XPath expressions is now supported.
Version 0.2
diff --git a/markup/core.py b/markup/core.py
--- a/markup/core.py
+++ b/markup/core.py
@@ -498,6 +498,11 @@
>>> qname in Namespace('http://www.w3.org/2002/06/xhtml2')
False
"""
+ def __new__(cls, uri):
+ if type(uri) is cls:
+ return uri
+ return object.__new__(cls, uri)
+
def __init__(self, uri):
self.uri = unicode(uri)
diff --git a/markup/path.py b/markup/path.py
--- a/markup/path.py
+++ b/markup/path.py
@@ -34,7 +34,8 @@
from math import ceil, floor
import re
-from markup.core import Stream, START, END, TEXT, COMMENT, PI
+from markup.core import Stream, Attrs, Namespace, QName
+from markup.core import START, END, TEXT, COMMENT, PI
__all__ = ['Path', 'PathSyntaxError']
@@ -86,11 +87,11 @@
for axis, nodetest, predicates in path:
steps.append('%s::%s' % (axis, nodetest))
for predicate in predicates:
- steps.append('[%s]' % predicate)
+ steps[-1] += '[%s]' % predicate
paths.append('/'.join(steps))
return '<%s "%s">' % (self.__class__.__name__, '|'.join(paths))
- def select(self, stream, variables=None):
+ def select(self, stream, namespaces=None, variables=None):
"""Returns a substream of the given stream that matches the path.
If there are no matches, this method returns an empty stream.
@@ -105,13 +106,19 @@
Text
@param stream: the stream to select from
+ @param namespaces: (optional) a mapping of namespace prefixes to URIs
+ @param variables: (optional) a mapping of variable names to values
@return: the substream matching the path, or an empty stream
"""
+ if namespaces is None:
+ namespaces = {}
+ if variables is None:
+ variables = {}
stream = iter(stream)
def _generate():
test = self.test()
for kind, data, pos in stream:
- result = test(kind, data, pos, variables)
+ result = test(kind, data, pos, namespaces, variables)
if result is True:
yield kind, data, pos
depth = 1
@@ -122,7 +129,7 @@
elif subkind is END:
depth -= 1
yield subkind, subdata, subpos
- test(subkind, subdata, subpos, variables)
+ test(subkind, subdata, subpos, namespaces, variables)
elif result:
yield result
return Stream(_generate())
@@ -132,21 +139,24 @@
a specific stream event.
The function returned expects the positional arguments `kind`, `data`,
- and `pos`, i.e. basically an unpacked stream event. If the path matches
- the event, the function returns the match (for example, a `START` or
- `TEXT` event.) Otherwise, it returns `None`.
+ `pos` (basically an unpacked stream event), as well as `namespaces`
+ and `variables`. The latter two are a mapping of namespace prefixes to
+ URIs, and a mapping of variable names to values, respectively.
+
+ If the path matches the event, the function returns the match (for
+ example, a `START` or `TEXT` event.) Otherwise, it returns `None`.
>>> from markup.input import XML
>>> xml = XML('')
>>> test = Path('child').test()
>>> for kind, data, pos in xml:
- ... if test(kind, data, pos, {}):
+ ... if test(kind, data, pos, {}, {}):
... print kind, data
START (u'child', [(u'id', u'2')])
"""
paths = [(steps, len(steps), [0], []) for steps in self.paths]
- def _test(kind, data, pos, variables):
+ def _test(kind, data, pos, namespaces, variables):
for steps, size, stack, cutoff in paths:
# Manage the stack that tells us "where we are" in the stream
if kind is END:
@@ -178,7 +188,7 @@
last_step = cursor + 1 == size
# Perform the actual node test
- matched = nodetest(kind, data, pos, variables)
+ matched = nodetest(kind, data, pos, namespaces, variables)
# The node test matched
if matched:
@@ -186,7 +196,8 @@
# Check all the predicates for this step
if predicates:
for predicate in predicates:
- if not predicate(kind, data, pos, variables):
+ if not predicate(kind, data, pos, namespaces,
+ variables):
matched = None
break
@@ -234,7 +245,8 @@
if k is DESCENDANT or k is DESCENDANT_OR_SELF]
backsteps.reverse()
for axis, nodetest, predicates in backsteps:
- matched = nodetest(kind, data, pos, variables)
+ matched = nodetest(kind, data, pos, namespaces,
+ variables)
if not matched:
cursor -= 1
cutoff[:] = []
@@ -360,10 +372,20 @@
return axis, nodetest, predicates
def _node_test(self, axis=None):
- test = None
- if self.peek_token() in ('(', '()'): # Node type test
+ test = prefix = None
+ next_token = self.peek_token()
+ if next_token in ('(', '()'): # Node type test
test = self._node_type()
+ elif next_token == ':': # Namespace prefix
+ prefix = self.cur_token
+ self.next_token()
+ localname = self.next_token()
+ if localname == '*':
+ test = QualifiedPrincipalTypeTest(axis, prefix)
+ else:
+ test = QualifiedNameTest(axis, prefix, localname)
+
else: # Name test
if self.cur_token == '*':
test = PrincipalTypeTest(axis)
@@ -492,7 +514,7 @@
__slots__ = ['principal_type']
def __init__(self, principal_type):
self.principal_type = principal_type
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
if kind is START:
if self.principal_type is ATTRIBUTE:
return data[1] or None
@@ -501,6 +523,24 @@
def __repr__(self):
return '*'
+class QualifiedPrincipalTypeTest(object):
+ """Node test that matches any event with the given principal type in a
+ specific namespace."""
+ __slots__ = ['principal_type', 'prefix']
+ def __init__(self, principal_type, prefix):
+ self.principal_type = principal_type
+ self.prefix = prefix
+ def __call__(self, kind, data, pos, namespaces, variables):
+ namespace = Namespace(namespaces.get(self.prefix))
+ if kind is START:
+ if self.principal_type is ATTRIBUTE and data[1]:
+ return Attrs([(name, value) for name, value in data[1]
+ if name in namespace]) or None
+ else:
+ return data[0] in namespace
+ def __repr__(self):
+ return '%s:*' % self.prefix
+
class LocalNameTest(object):
"""Node test that matches any event with the given prinipal type and
local name.
@@ -509,7 +549,7 @@
def __init__(self, principal_type, name):
self.principal_type = principal_type
self.name = name
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
if kind is START:
if self.principal_type is ATTRIBUTE and self.name in data[1]:
return TEXT, data[1].get(self.name), pos
@@ -518,10 +558,29 @@
def __repr__(self):
return self.name
+class QualifiedNameTest(object):
+ """Node test that matches any event with the given prinipal type and
+ qualified name.
+ """
+ __slots__ = ['principal_type', 'prefix', 'name']
+ def __init__(self, principal_type, prefix, name):
+ self.principal_type = principal_type
+ self.prefix = prefix
+ self.name = name
+ def __call__(self, kind, data, pos, namespaces, variables):
+ qname = QName('%s}%s' % (namespaces.get(self.prefix), self.name))
+ if kind is START:
+ if self.principal_type is ATTRIBUTE and qname in data[1]:
+ return TEXT, data[1].get(qname), pos
+ else:
+ return data[0] == qname
+ def __repr__(self):
+ return '%s:%s' % (self.prefix, self.name)
+
class CommentNodeTest(object):
"""Node test that matches any comment events."""
__slots__ = []
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
return kind is COMMENT and (kind, data, pos)
def __repr__(self):
return 'comment()'
@@ -529,7 +588,7 @@
class NodeTest(object):
"""Node test that matches any node."""
__slots__ = []
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
if kind is START:
return True
return kind, data, pos
@@ -541,7 +600,7 @@
__slots__ = ['target']
def __init__(self, target=None):
self.target = target
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
if kind is PI and (not self.target or data[0] == self.target):
return (kind, data, pos)
def __repr__(self):
@@ -553,7 +612,7 @@
class TextNodeTest(object):
"""Node test that matches any text event."""
__slots__ = []
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
return kind is TEXT and (kind, data, pos)
def __repr__(self):
return 'text()'
@@ -574,8 +633,8 @@
__slots__ = ['expr']
def __init__(self, expr):
self.expr = expr
- def __call__(self, kind, data, pos, variables):
- val = self.expr(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ val = self.expr(kind, data, pos, namespaces, variables)
if type(val) is tuple:
val = val[1]
return bool(val)
@@ -589,8 +648,8 @@
__slots__ = ['number']
def __init__(self, number):
self.number = number
- def __call__(self, kind, data, pos, variables):
- number = self.number(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ number = self.number(kind, data, pos, namespaces, variables)
if type(number) is tuple:
number = number[1]
return ceil(float(number))
@@ -604,9 +663,10 @@
__slots__ = ['exprs']
def __init__(self, *exprs):
self.exprs = exprs
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
strings = []
- for item in [expr(kind, data, pos, variables) for expr in self.exprs]:
+ for item in [expr(kind, data, pos, namespaces, variables)
+ for expr in self.exprs]:
if type(item) is tuple:
assert item[0] is TEXT
item = item[1]
@@ -623,11 +683,11 @@
def __init__(self, string1, string2):
self.string1 = string1
self.string2 = string2
- def __call__(self, kind, data, pos, variables):
- string1 = self.string1(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ string1 = self.string1(kind, data, pos, namespaces, variables)
if type(string1) is tuple:
string1 = string1[1]
- string2 = self.string2(kind, data, pos, variables)
+ string2 = self.string2(kind, data, pos, namespaces, variables)
if type(string2) is tuple:
string2 = string2[1]
return string2 in string1
@@ -637,7 +697,7 @@
class FalseFunction(Function):
"""The `false` function, which always returns the boolean `false` value."""
__slots__ = []
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
return False
def __repr__(self):
return 'false()'
@@ -649,8 +709,8 @@
__slots__ = ['number']
def __init__(self, number):
self.number = number
- def __call__(self, kind, data, pos, variables):
- number = self.number(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ number = self.number(kind, data, pos, namespaces, variables)
if type(number) is tuple:
number = number[1]
return floor(float(number))
@@ -662,7 +722,7 @@
element.
"""
__slots__ = []
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
if kind is START:
return TEXT, data[0].localname, pos
def __repr__(self):
@@ -673,7 +733,7 @@
element.
"""
__slots__ = []
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
if kind is START:
return TEXT, data[0], pos
def __repr__(self):
@@ -684,7 +744,7 @@
current element.
"""
__slots__ = []
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
if kind is START:
return TEXT, data[0].namespace, pos
def __repr__(self):
@@ -697,8 +757,8 @@
__slots__ = ['expr']
def __init__(self, expr):
self.expr = expr
- def __call__(self, kind, data, pos, variables):
- return not self.expr(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ return not self.expr(kind, data, pos, namespaces, variables)
def __repr__(self):
return 'not(%s)' % self.expr
@@ -711,8 +771,8 @@
_normalize = re.compile(r'\s{2,}').sub
def __init__(self, expr):
self.expr = expr
- def __call__(self, kind, data, pos, variables):
- string = self.expr(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ string = self.expr(kind, data, pos, namespaces, variables)
if type(string) is tuple:
string = string[1]
return self._normalize(' ', string.strip())
@@ -724,8 +784,8 @@
__slots__ = ['expr']
def __init__(self, expr):
self.expr = expr
- def __call__(self, kind, data, pos, variables):
- val = self.expr(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ val = self.expr(kind, data, pos, namespaces, variables)
if type(val) is tuple:
val = val[1]
return float(val)
@@ -739,8 +799,8 @@
__slots__ = ['number']
def __init__(self, number):
self.number = number
- def __call__(self, kind, data, pos, variables):
- number = self.number(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ number = self.number(kind, data, pos, namespaces, variables)
if type(number) is tuple:
number = number[1]
return round(float(number))
@@ -755,11 +815,11 @@
def __init__(self, string1, string2):
self.string1 = string2
self.string2 = string2
- def __call__(self, kind, data, pos, variables):
- string1 = self.string1(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ string1 = self.string1(kind, data, pos, namespaces, variables)
if type(string1) is tuple:
string1 = string1[1]
- string2 = self.string2(kind, data, pos, variables)
+ string2 = self.string2(kind, data, pos, namespaces, variables)
if type(string2) is tuple:
string2 = string2[1]
return string1.startswith(string2)
@@ -773,8 +833,8 @@
__slots__ = ['expr']
def __init__(self, expr):
self.expr = expr
- def __call__(self, kind, data, pos, variables):
- string = self.expr(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ string = self.expr(kind, data, pos, namespaces, variables)
if type(string) is tuple:
string = string[1]
return len(string)
@@ -790,16 +850,16 @@
self.string = string
self.start = start
self.length = length
- def __call__(self, kind, data, pos, variables):
- string = self.string(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ string = self.string(kind, data, pos, namespaces, variables)
if type(string) is tuple:
string = string[1]
- start = self.start(kind, data, pos, variables)
+ start = self.start(kind, data, pos, namespaces, variables)
if type(start) is tuple:
start = start[1]
length = 0
if self.length is not None:
- length = self.length(kind, data, pos, variables)
+ length = self.length(kind, data, pos, namespaces, variables)
if type(length) is tuple:
length = length[1]
return string[int(start):len(string) - int(length)]
@@ -818,11 +878,11 @@
def __init__(self, string1, string2):
self.string1 = string1
self.string2 = string2
- def __call__(self, kind, data, pos, variables):
- string1 = self.string1(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ string1 = self.string1(kind, data, pos, namespaces, variables)
if type(string1) is tuple:
string1 = string1[1]
- string2 = self.string2(kind, data, pos, variables)
+ string2 = self.string2(kind, data, pos, namespaces, variables)
if type(string2) is tuple:
string2 = string2[1]
index = string1.find(string2)
@@ -840,11 +900,11 @@
def __init__(self, string1, string2):
self.string1 = string1
self.string2 = string2
- def __call__(self, kind, data, pos, variables):
- string1 = self.string1(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ string1 = self.string1(kind, data, pos, namespaces, variables)
if type(string1) is tuple:
string1 = string1[1]
- string2 = self.string2(kind, data, pos, variables)
+ string2 = self.string2(kind, data, pos, namespaces, variables)
if type(string2) is tuple:
string2 = string2[1]
index = string1.find(string2)
@@ -863,14 +923,14 @@
self.string = string
self.fromchars = fromchars
self.tochars = tochars
- def __call__(self, kind, data, pos, variables):
- string = self.string(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ string = self.string(kind, data, pos, namespaces, variables)
if type(string) is tuple:
string = string[1]
- fromchars = self.fromchars(kind, data, pos, variables)
+ fromchars = self.fromchars(kind, data, pos, namespaces, variables)
if type(fromchars) is tuple:
fromchars = fromchars[1]
- tochars = self.tochars(kind, data, pos, variables)
+ tochars = self.tochars(kind, data, pos, namespaces, variables)
if type(tochars) is tuple:
tochars = tochars[1]
table = dict(zip([ord(c) for c in fromchars],
@@ -883,7 +943,7 @@
class TrueFunction(Function):
"""The `true` function, which always returns the boolean `true` value."""
__slots__ = []
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
return True
def __repr__(self):
return 'true()'
@@ -912,7 +972,7 @@
__slots__ = ['text']
def __init__(self, text):
self.text = text
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
return TEXT, self.text, (None, -1, -1)
def __repr__(self):
return '"%s"' % self.text
@@ -922,7 +982,7 @@
__slots__ = ['number']
def __init__(self, number):
self.number = number
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
return TEXT, self.number, (None, -1, -1)
def __repr__(self):
return str(self.number)
@@ -932,7 +992,7 @@
__slots__ = ['name']
def __init__(self, name):
self.name = name
- def __call__(self, kind, data, pos, variables):
+ def __call__(self, kind, data, pos, namespaces, variables):
return TEXT, variables.get(self.name), (None, -1, -1)
def __repr__(self):
return str(self.name)
@@ -945,13 +1005,13 @@
def __init__(self, lval, rval):
self.lval = lval
self.rval = rval
- def __call__(self, kind, data, pos, variables):
- lval = self.lval(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ lval = self.lval(kind, data, pos, namespaces, variables)
if type(lval) is tuple:
lval = lval[1]
if not lval:
return False
- rval = self.rval(kind, data, pos, variables)
+ rval = self.rval(kind, data, pos, namespaces, variables)
if type(rval) is tuple:
rval = rval[1]
return bool(rval)
@@ -964,11 +1024,11 @@
def __init__(self, lval, rval):
self.lval = lval
self.rval = rval
- def __call__(self, kind, data, pos, variables):
- lval = self.lval(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ lval = self.lval(kind, data, pos, namespaces, variables)
if type(lval) is tuple:
lval = lval[1]
- rval = self.rval(kind, data, pos, variables)
+ rval = self.rval(kind, data, pos, namespaces, variables)
if type(rval) is tuple:
rval = rval[1]
return lval == rval
@@ -981,11 +1041,11 @@
def __init__(self, lval, rval):
self.lval = lval
self.rval = rval
- def __call__(self, kind, data, pos, variables):
- lval = self.lval(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ lval = self.lval(kind, data, pos, namespaces, variables)
if type(lval) is tuple:
lval = lval[1]
- rval = self.rval(kind, data, pos, variables)
+ rval = self.rval(kind, data, pos, namespaces, variables)
if type(rval) is tuple:
rval = rval[1]
return lval != rval
@@ -998,13 +1058,13 @@
def __init__(self, lval, rval):
self.lval = lval
self.rval = rval
- def __call__(self, kind, data, pos, variables):
- lval = self.lval(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ lval = self.lval(kind, data, pos, namespaces, variables)
if type(lval) is tuple:
lval = lval[1]
if lval:
return True
- rval = self.rval(kind, data, pos, variables)
+ rval = self.rval(kind, data, pos, namespaces, variables)
if type(rval) is tuple:
rval = rval[1]
return bool(rval)
@@ -1017,11 +1077,11 @@
def __init__(self, lval, rval):
self.lval = lval
self.rval = rval
- def __call__(self, kind, data, pos, variables):
- lval = self.lval(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ lval = self.lval(kind, data, pos, namespaces, variables)
if type(lval) is tuple:
lval = lval[1]
- rval = self.rval(kind, data, pos, variables)
+ rval = self.rval(kind, data, pos, namespaces, variables)
if type(rval) is tuple:
rval = rval[1]
return float(lval) > float(rval)
@@ -1034,11 +1094,11 @@
def __init__(self, lval, rval):
self.lval = lval
self.rval = rval
- def __call__(self, kind, data, pos, variables):
- lval = self.lval(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ lval = self.lval(kind, data, pos, namespaces, variables)
if type(lval) is tuple:
lval = lval[1]
- rval = self.rval(kind, data, pos, variables)
+ rval = self.rval(kind, data, pos, namespaces, variables)
if type(rval) is tuple:
rval = rval[1]
return float(lval) > float(rval)
@@ -1051,11 +1111,11 @@
def __init__(self, lval, rval):
self.lval = lval
self.rval = rval
- def __call__(self, kind, data, pos, variables):
- lval = self.lval(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ lval = self.lval(kind, data, pos, namespaces, variables)
if type(lval) is tuple:
lval = lval[1]
- rval = self.rval(kind, data, pos, variables)
+ rval = self.rval(kind, data, pos, namespaces, variables)
if type(rval) is tuple:
rval = rval[1]
return float(lval) >= float(rval)
@@ -1068,11 +1128,11 @@
def __init__(self, lval, rval):
self.lval = lval
self.rval = rval
- def __call__(self, kind, data, pos, variables):
- lval = self.lval(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ lval = self.lval(kind, data, pos, namespaces, variables)
if type(lval) is tuple:
lval = lval[1]
- rval = self.rval(kind, data, pos, variables)
+ rval = self.rval(kind, data, pos, namespaces, variables)
if type(rval) is tuple:
rval = rval[1]
return float(lval) < float(rval)
@@ -1085,11 +1145,11 @@
def __init__(self, lval, rval):
self.lval = lval
self.rval = rval
- def __call__(self, kind, data, pos, variables):
- lval = self.lval(kind, data, pos, variables)
+ def __call__(self, kind, data, pos, namespaces, variables):
+ lval = self.lval(kind, data, pos, namespaces, variables)
if type(lval) is tuple:
lval = lval[1]
- rval = self.rval(kind, data, pos, variables)
+ rval = self.rval(kind, data, pos, namespaces, variables)
if type(rval) is tuple:
rval = rval[1]
return float(lval) <= float(rval)
diff --git a/markup/template.py b/markup/template.py
--- a/markup/template.py
+++ b/markup/template.py
@@ -1010,6 +1010,7 @@
"""
if match_templates is None:
match_templates = ctxt._match_templates
+ nsprefix = {} # mapping of namespace prefixes to URIs
tail = []
def _strip(stream):
@@ -1037,12 +1038,12 @@
for idx, (test, path, template, directives) in \
enumerate(match_templates):
- if test(kind, data, pos, ctxt) is True:
+ if test(kind, data, pos, nsprefix, ctxt) is True:
# Let the remaining match templates know about the event so
# they get a chance to update their internal state
for test in [mt[0] for mt in match_templates[idx + 1:]]:
- test(kind, data, pos, ctxt)
+ test(kind, data, pos, nsprefix, ctxt)
# Consume and store all events until an end event
# corresponding to this start event is encountered
@@ -1051,7 +1052,7 @@
kind, data, pos = tail[0]
for test in [mt[0] for mt in match_templates]:
- test(kind, data, pos, ctxt)
+ test(kind, data, pos, nsprefix, ctxt)
# Make the select() function available in the body of the
# match template
diff --git a/markup/tests/path.py b/markup/tests/path.py
--- a/markup/tests/path.py
+++ b/markup/tests/path.py
@@ -404,7 +404,44 @@
xml = XML('bar')
path = Path('*[name()=$bar]')
variables = {'bar': 'foo'}
- self.assertEqual('bar', path.select(xml, variables).render())
+ self.assertEqual('bar',
+ path.select(xml, variables=variables).render())
+
+ def test_name_with_namespace(self):
+ xml = XML('bar')
+ path = Path('f:foo')
+ self.assertEqual('', repr(path))
+ namespaces = {'f': 'FOO'}
+ self.assertEqual('bar',
+ path.select(xml, namespaces=namespaces).render())
+
+ def test_wildcard_with_namespace(self):
+ xml = XML('bar')
+ path = Path('f:*')
+ self.assertEqual('', repr(path))
+ namespaces = {'f': 'FOO'}
+ self.assertEqual('bar',
+ path.select(xml, namespaces=namespaces).render())
+
+ # FIXME: the following two don't work due to a problem in XML serialization:
+ # attributes that would need a namespace prefix that isn't in the
+ # prefix map would need to get an artificial prefix, but currently
+ # don't
+ #
+ #def test_attrname_with_namespace(self):
+ # xml = XML('')
+ # path = Path('foo[@f:bar]')
+ # print path
+ # namespaces = {'f': 'FOO'}
+ # self.assertEqual('',
+ # path.select(xml, namespaces=namespaces).render())
+ #
+ #def test_attrwildcard_with_namespace(self):
+ # xml = XML('')
+ # path = Path('foo[@f:*]')
+ # namespaces = {'f': 'FOO'}
+ # self.assertEqual('',
+ # path.select(xml, namespaces=namespaces).render())
def suite():