Commit 48605a2b authored by Guido van Rossum's avatar Guido van Rossum

Quite a bit of refactoring, and macro slots now work.

- The DOMVisitor class is simplified a bit; it doesn't visit
  attributes for you and it doesn't define endVisitElement().

- The CopyingDOMVisitor class is fixed to cope with this; instead of
  endVisitElement() it defines and uses backUp(), with the same
  purpose.  It defines and uses copyAllAttributes() and
  copyAttribute() to deal with attributes.

- The TALVisitor class is refactored so that the processing of METAL
  and TAL attributes is done more orderly (I discovered
  getAttributeNS() :-).

- Used a different way to split parts into semicolon-separated parts
  with doubling used to quote semicolons.

- Sped up the macro indexer by using a recursive function with an
  explicit argument rather than a visitor class.

- Added a slot indexer that works the same way.  (The macro and slot
  indexers have a lot in common, but they're still so small that I
  didn't bother factoring it out.  Later.)

- The runtest.sh script now takes optional command line arguments
  (full pathnames of testfiles) to specify a set of tests to run.

- The timer.py script was adapted to use the new macroIndexer().
parent 23700b46
......@@ -103,9 +103,11 @@ class CopyingDOMVisitor(DOMVisitor):
def visitElement(self, node):
self.copyElement(node)
self.copyAllAttributes(node)
DOMVisitor.visitElement(self, node)
self.backUp()
def endVisitElement(self, node):
def backUp(self):
self.curNode = self.curNode.parentNode
def copyElement(self, node):
......@@ -120,17 +122,24 @@ class CopyingDOMVisitor(DOMVisitor):
self.curNode.appendChild(newNode)
self.curNode = newNode
def copyAllAttributes(self, node):
for attr in node.attributes.values():
self.copyAttribute(attr)
def copyAttribute(self, attr):
if attr.namespaceURI:
self.curNode.setAttributeNS(
attr.namespaceURI, attr.nodeName, attr.nodeValue)
else:
self.curNode.setAttribute(attr.nodeName, attr.nodeValue)
def visitText(self, node):
newNode = self.newDocument.createTextNode(node.nodeValue)
self.curNode.appendChild(newNode)
def visitComment(self, node):
newNode = self.newDocument.createComment(node.nodeValue)
self.curNode.appendChild(newNode)
def visitAttribute(self, node):
if node.namespaceURI:
self.curNode.setAttributeNS(
node.namespaceURI, node.nodeName, node.nodeValue)
else:
self.curNode.setAttribute(node.nodeName, node.nodeValue)
if self.newDocument:
newNode = self.newDocument.createComment(node.nodeValue)
self.curNode.appendChild(newNode)
# XXX Else, this is a comment before the documentElement; lose it.
......@@ -114,11 +114,10 @@ class DOMVisitor:
implementation).
You can influence which nodes are visited in which order by
overriding visitAllChildren() and visitAllAttributes(), and/or by
overriding visitDocument() and visitElement(). If you override
the latter two, be careful to either call the base class method or
call visitAllAttributes(), visitAllChildren() and
endVisitElement() as shown in their base class implementations,
overriding visitAllChildren(), and/or by overriding
visitDocument() and visitElement(). If you override the latter
two, be careful to either call the base class method or call
visitAllChildren() as shown in their base class implementations,
otherwise the tree traversal will break.
"""
......@@ -154,7 +153,7 @@ class DOMVisitor:
# Dictionary mapping node types to method names, used in visitNode
visitSwitch = {
Node.ELEMENT_NODE: "visitElement",
Node.ATTRIBUTE_NODE: "visitAttr",
Node.ATTRIBUTE_NODE: "visitAttribute",
Node.TEXT_NODE: "visitText",
Node.CDATA_SECTION_NODE: "visitCDATASection",
Node.ENTITY_REFERENCE_NODE: "visitEntityReference",
......@@ -185,22 +184,10 @@ class DOMVisitor:
"""
Visit an element node.
This calls visitAllAttributes() to visit the attributes, and
visitAllChildren() to recurse into the document tree. It also
calls endVisitElement() in order to signal the end of the visit.
This calls visitAllChildren() to recurse into the document
tree.
"""
self.visitAllAttributes(node)
self.visitAllChildren(node)
self.endVisitElement(node)
def endVisitElement(self, node):
"""
This method is called after visitElement has finished visiting
all its children. It is useful for processing to be done
after the element's subtree has been visited, e.g. spitting
out an end tag or closing a scope.
"""
pass
def visitAllChildren(self, node):
"""
......@@ -209,13 +196,6 @@ class DOMVisitor:
for child in node.childNodes:
self.visitNode(child)
def visitAllAttributes(self, node):
"""
Call visitAttribute() for each attribute of the given node.
"""
for attr in node.attributes.values():
self.visitAttribute(attr)
def visitAttribute(self, node):
"""
Override this empty method to visit an attribute node.
......
......@@ -112,142 +112,100 @@ class TALVisitor(CopyingDOMVisitor):
self.document = document
self.engine = engine
self.currentMacro = None
self.originalNode = None
self.slotIndex = None
def visitElement(self, node):
self.engine.beginScope()
if not self.checkTAL(node):
if not node.attributes:
CopyingDOMVisitor.visitElement(self, node)
self.engine.endScope()
return
macroName = node.getAttributeNS(ZOPE_METAL_NS, "use-macro")
if macroName:
macroNode = self.findMacro(macroName)
if macroNode:
self.expandMacro(macroNode, node)
return
if self.currentMacro and self.slotIndex and self.originalNode:
slotName = node.getAttributeNS(ZOPE_METAL_NS, "define-slot")
if slotName:
slotNode = self.slotIndex.get(slotName)
if slotNode:
self.visitElement(slotNode)
return
if node.getAttributeNS(ZOPE_TAL_NS, "omit"):
# XXX Problem: this DOM implementation doesn't
# differentiate between argument empty and argument
# absent.
# XXX Question: should 'omit' be done before or after
# 'define'?
return
defines = node.getAttributeNS(ZOPE_TAL_NS, "define")
if defines:
self.engine.beginScope()
self.doDefine(defines)
self.finishElement(node)
self.engine.endScope()
else:
self.finishElement(node)
def checkTAL(self, node):
# Do TAL expansion. Return value is 1 if node expansion
# complete, 0 if original node should be copied.
attrs = node.attributes
if not attrs:
return 0
# Collect TAL attributes
setOps = []
ifOps = []
modOps = []
attrOps = []
omit = 0
macroNode = 0
for attr in attrs.values():
if attr.namespaceURI == ZOPE_TAL_NS:
name = attr.localName
if name == "define":
setOps.append(attr)
elif name == "condition":
ifOps.append(attr)
elif name in ("insert", "replace"):
modOps.append(attr)
elif name == "attributes":
attrOps.append(attr)
elif name == "omit":
omit = 1
else:
print "Unrecognized ZOPE/TAL attribute:",
print "%s=%s" % (attr.nodeName, `attr.nodeValue`)
# This doesn't stop us from doing the rest!
elif attr.namespaceURI == ZOPE_METAL_NS:
name = attr.localName
if name == "define-macro":
pass
elif name == "define-slot":
pass
elif name == "use-macro":
macroNode = self.findMacro(attr.nodeValue)
elif name == "use-slot":
pass
else:
print "Unrecognized ZOPE/METAL attribute:",
print "%s=%s" % (attr.nodeName, `attr.nodeValue`)
# If any of these assertions fail, the DOM is broken
assert len(setOps) <= 1
assert len(ifOps) <= 1
assert len(attrOps) <= 1
# Macro expansion overrides anything else:
if macroNode:
self.expandMacro(macroNode)
return 1
# Execute TAL attributes in proper order:
# 0. omit, 1. define, 2. condition, 3. insert/replace, 4. attributes
if omit:
if setOps or ifOps or modOps or attrOps:
print "Note: z:omit conflicts with all other z:... attributes"
return 1
if setOps:
[attr] = setOps
self.doDefine(node, attr.nodeValue)
if ifOps:
[attr] = ifOps
if not self.doCondition(node, attr.nodeValue):
return 1
def finishElement(self, node):
condition = node.getAttributeNS(ZOPE_TAL_NS, "condition")
if condition and not self.engine.evaluateBoolean(condition):
return
attrDict = {}
if attrOps:
[attr] = attrOps
attrDict = self.prepAttr(node, attr.nodeValue)
if len(modOps) > 1:
names = map(lambda a: a.nodeName, modOps)
print "Mutually exclusive ZOPE/TAL attributes:", [names]
elif modOps:
[attr] = modOps
return self.doModify(
node, attr.localName, attr.nodeValue, attrDict)
if attrDict:
attributes = node.getAttributeNS(ZOPE_TAL_NS, "attributes")
if attributes:
attrDict = self.parseAttributeReplacements(attributes)
insert = node.getAttributeNS(ZOPE_TAL_NS, "insert")
replace = node.getAttributeNS(ZOPE_TAL_NS, "replace")
if not (insert or replace):
done = 0
else:
if insert and replace:
print "Warning: z:insert overrides z:replace on the same node"
done = self.doModify(node, insert, insert or replace, attrDict)
if not done:
self.copyElement(node)
self.copyAttributes(node, attrDict)
self.visitAllChildren(node)
self.endVisitElement(node)
return 1
return 0
self.backUp()
def findMacro(self, macroName):
# XXX This is not written for speed :-)
doc, localName = self.engine.findMacroDocument(macroName)
if not doc:
doc = self.document
macroDict = MacroIndexer(doc)()
macroDict = macroIndexer(doc)
if macroDict.has_key(localName):
return macroDict[localName]
else:
print "No macro found:", macroName
return None
def expandMacro(self, node):
assert node.nodeType == Node.ELEMENT_NODE
saveCurrentMacro = self.currentMacro
self.currentMacro = node
self.engine.beginScope()
if not self.checkTAL(node):
self.copyElement(node)
self.copyAttributes(node, {})
self.visitAllChildren(node)
self.endVisitElement(node)
self.engine.endScope()
self.currentMacro = saveCurrentMacro
def expandMacro(self, macroNode, originalNode):
save = self.currentMacro, self.slotIndex, self.originalNode
self.currentMacro = macroNode
self.slotIndex = slotIndexer(originalNode)
self.originalNode = originalNode
self.visitElement(macroNode)
self.currentMacro, self.slotIndex, self.originalNode = save
def doDefine(self, node, arg):
def doDefine(self, arg):
for part in self.splitParts(arg):
m = re.match(
r"\s*(global\s+|local\s+)?(%s)\s+as\s+(.*)" % NAME_RE, part)
r"\s*(?:(global|local)\s+)?(%s)\s+as\s+(.*)" % NAME_RE, part)
if not m:
print "Bad syntax in z:define argument:", `part`
else:
scope, name, expr = m.group(1, 2, 3)
scope = string.strip(scope or "local")
scope = scope or "local"
value = self.engine.evaluateValue(expr)
if scope == "local":
self.engine.setLocal(name, value)
else:
self.engine.setGlobal(name, value)
def doCondition(self, node, arg):
return self.engine.evaluateBoolean(arg)
def doModify(self, node, cmdName, arg, attrDict):
assert cmdName in ("insert", "replace")
inserting = (cmdName == "insert")
def doModify(self, node, inserting, arg, attrDict):
m = re.match(
r"(?:\s*(text|structure|for\s+(%s)\s+in)\s+)?(.*)" % NAME_RE, arg)
if not m:
......@@ -274,7 +232,7 @@ class TALVisitor(CopyingDOMVisitor):
for item in sequence:
self.engine.setLocal(name, item)
self.visitAllChildren(node)
self.endVisitElement(node)
self.backUp()
return 1
def doReplaceLoop(self, node, key, name, expr, attrDict):
......@@ -287,7 +245,7 @@ class TALVisitor(CopyingDOMVisitor):
self.copyElement(node)
self.copyAttributes(node, attrDict)
self.visitAllChildren(node)
self.endVisitElement(node)
self.backUp()
return 1
def doNonLoop(self, node, inserting, key, expr, attrDict):
......@@ -320,7 +278,7 @@ class TALVisitor(CopyingDOMVisitor):
attrValue = attr.nodeValue
if attrDict.has_key(attrName):
expr = attrDict[attrName]
if string.strip(expr) == "nothing":
if expr == "nothing":
continue
attrValue = self.engine.evaluateText(expr)
if attrValue is None:
......@@ -335,7 +293,7 @@ class TALVisitor(CopyingDOMVisitor):
else:
self.curNode.setAttribute(attrName, attrValue)
def prepAttr(self, node, arg):
def parseAttributeReplacements(self, arg):
dict = {}
for part in self.splitParts(arg):
m = re.match(r"\s*([^\s=]+)\s*=\s*(.*)", part)
......@@ -352,36 +310,55 @@ class TALVisitor(CopyingDOMVisitor):
def splitParts(self, arg):
# Break in pieces at undoubled semicolons and
# change double semicolons to singles:
arg = string.replace(arg, ";;", "\0")
parts = string.split(arg, ';')
while "" in parts:
i = parts.index("")
if i+1 >= len(parts):
break
parts[i-1:i+2] = ["%s;%s" % (parts[i-1], parts[i+1])]
parts = map(lambda s: string.replace(s, "\0", ";;"), parts)
return parts
class MacroIndexer(DOMVisitor):
"""
Helper class to create an index of all macros in a DOM tree.
def macroIndexer(document):
"""
Return a dictionary containing all define-macro nodes in a document.
def __call__(self):
self.macroIndex = {}
DOMVisitor.__call__(self)
return self.macroIndex
def visitElement(self, node):
macroName = node.getAttributeNS(ZOPE_METAL_NS, "define-macro")
if macroName:
self.defineMacro(macroName, node)
# No need to call visitAllAttributes() or endVisitElement()
self.visitAllChildren(node)
The dictionary will have the form {macroName: node, ...}.
"""
macroIndex = {}
_macroVisitor(document.documentElement, macroIndex)
return macroIndex
def defineMacro(self, macroName, node):
if self.macroIndex.has_key(macroName):
def _macroVisitor(node, macroIndex, __elementNodeType=Node.ELEMENT_NODE):
# Internal routine to efficiently recurse down the tree of elements
macroName = node.getAttributeNS(ZOPE_METAL_NS, "define-macro")
if macroName:
if macroIndex.has_key(macroName):
print ("Duplicate macro definition: %s in <%s>" %
(macroName, node.nodeName))
else:
self.macroIndex[macroName] = node
macroIndex[macroName] = node
for child in node.childNodes:
if child.nodeType == __elementNodeType:
_macroVisitor(child, macroIndex)
def slotIndexer(rootNode):
"""
Return a dictionary containing all use-slot nodes in a subtree.
The dictionary will have the form {slotName: node, ...}.
"""
slotIndex = {}
_slotVisitor(rootNode, slotIndex)
return slotIndex
def _slotVisitor(node, slotIndex, __elementNodeType=Node.ELEMENT_NODE):
# Internal routine to efficiently recurse down the tree of elements
slotName = node.getAttributeNS(ZOPE_METAL_NS, "use-slot")
if slotName:
if slotIndex.has_key(slotName):
print ("Duplicate slot definition: %s in <%s>" %
(slotName, node.nodeName))
else:
slotIndex[slotName] = node
for child in node.childNodes:
if child.nodeType == __elementNodeType:
_slotVisitor(child, slotIndex)
......@@ -4,17 +4,17 @@
: ${TMPDIR=/tmp}
for test in test/test*.xml
for test in ${*-test/test*.xml}
do
out=` echo $test | sed 's,test/test,test/out,' `
out=` echo $test | sed 's,/[^/0-9]*\([0-9]*\).xml,/out\1.xml,' `
tmp=$TMPDIR/taltest$$`basename $test`
./driver.py $test >$tmp
if cmp -s $tmp $out
then
echo $test OK
else
echo $test failed -- diff follows
diff $out $tmp
echo "$test failed -- diff (expected vs. actual) follows"
diff $out $tmp
fi
rm $tmp
done
<?xml version="1.0" ?>
<table xmlns:m="http://xml.zope.org/namespaces/metal" m:define-macro="myTable">
<!-- macro definition with slots -->
<tr>
<td>Top Left</td>
<td>Top Right</td>
</tr>
<tr>
<td>Bottom left</td>
<td><span m:define-slot="bottomRight">Bottom Right</span></td>
</tr>
</table>
<?xml version="1.0" ?>
<table xmlns:m="http://xml.zope.org/namespaces/metal" m:use-macro="myTable">
<!-- macro definition with slots -->
<tr>
<td>Top Left</td>
<td>Top Right</td>
</tr>
<tr>
<td>Bottom left</td>
<td><span m:use-slot="bottomRight">
<h1>Some headline</h1>
<p>This is the real contents of the bottom right slot.</p>
<p>It is supposed to contain a lot of text. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb.</p>
<p>It is supposed to contain a lot of text. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb.</p>
<p>It is supposed to contain a lot of text. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb.</p>
</span></td>
</tr>
</table>
<?xml version="1.0" ?>
<table xmlns:m="http://xml.zope.org/namespaces/metal" m:define-macro="myTable">
<!-- macro definition with slots -->
<tr>
<td>Top Left</td>
<td>Top Right</td>
</tr>
<tr>
<td>Bottom left</td>
<td><span m:define-slot="bottomRight">Bottom Right</span></td>
</tr>
</table>
<?xml version="1.0" ?>
<table xmlns:m="http://xml.zope.org/namespaces/metal" m:use-macro="test/test7.xml/myTable">
<!-- macro use with slots -->
<tr>
<td>
<span m:use-slot="bottomRight">
<h1>Some headline</h1>
<p>This is the real contents of the bottom right slot.</p>
<p>It is supposed to contain a lot of text. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb.</p>
<p>It is supposed to contain a lot of text. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb.</p>
<p>It is supposed to contain a lot of text. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb.</p>
</span>
</td>
</tr>
</table>
<?xml version="1.0" ?>
<table xmlns:m="http://xml.zope.org/namespaces/metal" m:define-macro="myTable">
<!-- macro definition with slots -->
<tr>
<td>Top Left</td>
<td>Top Right</td>
</tr>
<tr>
<td>Bottom left</td>
<td><span m:define-slot="bottomRight">Bottom Right</span></td>
</tr>
</table>
<?xml version="1.0" ?>
<table xmlns:m="http://xml.zope.org/namespaces/metal" m:use-macro="myTable">
<!-- macro definition with slots -->
<tr>
<td>Top Left</td>
<td>Top Right</td>
</tr>
<tr>
<td>Bottom left</td>
<td><span m:use-slot="bottomRight">
<h1>Some headline</h1>
<p>This is the real contents of the bottom right slot.</p>
<p>It is supposed to contain a lot of text. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb.</p>
<p>It is supposed to contain a lot of text. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb.</p>
<p>It is supposed to contain a lot of text. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb.</p>
</span></td>
</tr>
</table>
<?xml version="1.0" ?>
<table xmlns:m="http://xml.zope.org/namespaces/metal" m:define-macro="myTable">
<!-- macro definition with slots -->
<tr>
<td>Top Left</td>
<td>Top Right</td>
</tr>
<tr>
<td>Bottom left</td>
<td><span m:define-slot="bottomRight">Bottom Right</span></td>
</tr>
</table>
<?xml version="1.0" ?>
<table xmlns:m="http://xml.zope.org/namespaces/metal" m:use-macro="test/test7.xml/myTable">
<!-- macro use with slots -->
<tr>
<td>
<span m:use-slot="bottomRight">
<h1>Some headline</h1>
<p>This is the real contents of the bottom right slot.</p>
<p>It is supposed to contain a lot of text. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb.</p>
<p>It is supposed to contain a lot of text. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb.</p>
<p>It is supposed to contain a lot of text. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb. Blah, blah, blab.
Blabber, blabber, blah. Baah, baah, barb.</p>
</span>
</td>
</tr>
</table>
......@@ -125,8 +125,8 @@ def timefunc(count, func, *args):
return result
def findmacros(doc):
from TALVisitor import MacroIndexer
return MacroIndexer(doc)()
from TALVisitor import macroIndexer
return macroIndexer(doc)
if __name__ == "__main__":
main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment