| # |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| # |
| |
| """ |
| Useful transforms for dom objects. |
| """ |
| from __future__ import absolute_import |
| |
| from . import dom |
| try: |
| from io import StringIO |
| except ImportError: |
| from cStringIO import StringIO |
| |
| |
| class Visitor: |
| |
| def descend(self, node): |
| for child in node.children: |
| child.dispatch(self) |
| |
| def node(self, node): |
| self.descend(node) |
| |
| def leaf(self, leaf): |
| pass |
| |
| |
| class Identity: |
| |
| def descend(self, node): |
| result = [] |
| for child in node.children: |
| result.append(child.dispatch(self)) |
| return result |
| |
| def default(self, tag): |
| result = dom.Tag(tag.name, *tag.attrs) |
| result.extend(self.descend(tag)) |
| return result |
| |
| def tree(self, tree): |
| result = dom.Tree() |
| result.extend(self.descend(tree)) |
| return result |
| |
| def tag(self, tag): |
| return self.default(tag) |
| |
| def leaf(self, leaf): |
| return leaf.__class__(leaf.data) |
| |
| |
| class Sexp(Identity): |
| |
| def __init__(self): |
| self.stack = [] |
| self.level = 0 |
| self.out = "" |
| |
| def open(self, s): |
| self.out += "(%s" % s |
| self.level += len(s) + 1 |
| self.stack.append(s) |
| |
| def line(self, s=""): |
| self.out = self.out.rstrip() |
| self.out += "\n" + " " * self.level + s |
| |
| def close(self): |
| s = self.stack.pop() |
| self.level -= len(s) + 1 |
| self.out = self.out.rstrip() |
| self.out += ")" |
| |
| def tree(self, tree): |
| self.open("+ ") |
| for child in tree.children: |
| self.line() |
| child.dispatch(self) |
| self.close() |
| |
| def tag(self, tag): |
| self.open("Node(%s) " % tag.name) |
| for child in tag.children: |
| self.line() |
| child.dispatch(self) |
| self.close() |
| |
| def leaf(self, leaf): |
| self.line("%s(%s)" % (leaf.__class__.__name__, leaf.data)) |
| |
| |
| class Output: |
| |
| def descend(self, node): |
| out = StringIO() |
| for child in node.children: |
| out.write(child.dispatch(self)) |
| return out.getvalue() |
| |
| def default(self, tag): |
| out = StringIO() |
| out.write("<%s" % tag.name) |
| for k, v in tag.attrs: |
| out.write(' %s="%s"' % (k, v)) |
| out.write(">") |
| out.write(self.descend(tag)) |
| if not tag.singleton: |
| out.write("</%s>" % tag.name) |
| return out.getvalue() |
| |
| def tree(self, tree): |
| return self.descend(tree) |
| |
| def tag(self, tag): |
| return self.default(tag) |
| |
| def data(self, leaf): |
| return leaf.data |
| |
| def entity(self, leaf): |
| return "&%s;" % leaf.data |
| |
| def character(self, leaf): |
| raise Exception("TODO") |
| |
| def comment(self, leaf): |
| return "<!-- %s -->" % leaf.data |
| |
| |
| class Empty(Output): |
| |
| def tag(self, tag): |
| return self.descend(tag) |
| |
| def data(self, leaf): |
| return "" |
| |
| def entity(self, leaf): |
| return "" |
| |
| def character(self, leaf): |
| return "" |
| |
| def comment(self, leaf): |
| return "" |
| |
| |
| class Text(Empty): |
| |
| def data(self, leaf): |
| return leaf.data |
| |
| def entity(self, leaf): |
| return "&%s;" % leaf.data |
| |
| def character(self, leaf): |
| # XXX: is this right? |
| return "&#%s;" % leaf.data |