Mercurial > projects > orange
view orange/xml/XMLDocument.d @ 26:78e5fef4bbf2 experimental
Third step in refactoring the API. Stating to add unit tests.
author | Jacob Carlborg <doob@me.com> |
---|---|
date | Tue, 19 Oct 2010 10:22:10 +0200 |
parents | 9a575087b961 |
children | 511d1ef4e299 |
line wrap: on
line source
/** * Copyright: Copyright (c) 2010 Jacob Carlborg. * Authors: Jacob Carlborg * Version: Initial created: Jun 26, 2010 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) */ module orange.xml.XMLDocument; version (Tango) { import tango.text.xml.DocPrinter; import tango.text.xml.Document; import tango.io.Stdout; import orange.core.string; } else { import std.string; import std.stdio; import orange.xml.PhobosXML; version = Phobos; } import orange.core.io; template Char (T) { version (Tango) { static if (is(T == char) || is(T == wchar) || is(T == dchar)) alias T Char; else static assert(false, `The given type "` ~ T.stringof ~ `" is not a vaild character type, valid types are "char", "wchar" and "dchar".`); } else { static if (is(T == char)) alias T Char; else static assert(false, `The given type "` ~ T.stringof ~ `" is not a vaild character type, the only valid type is "char".`); } } class XMLException : Exception { version (Tango) private alias long Line; else private alias size_t Line; this (string message, string file = null, Line line = 0) { super(message, file, line); } } final class XMLDocument (T = char) { version (Tango) { alias Document!(T) Doc; alias Doc.Node InternalNode; alias XmlPath!(T).NodeSet QueryNode; alias T[] tstring; alias Doc.Visitor VisitorType; } else { alias Document Doc; alias Element InternalNode; alias Element QueryNode; alias string tstring; alias Element[] VisitorType; } struct VisitorProxy { private VisitorType nodes; private static VisitorProxy opCall (VisitorType nodes) { VisitorProxy vp; vp.nodes = nodes; return vp; } bool exist () { version (Tango) return nodes.exist; else return nodes.length > 0; } int opApply (int delegate (ref Node) dg) { int result; foreach (n ; nodes) { auto p = Node(n); result = dg(p); if (result) break; } return result; } } struct Node { private InternalNode node; version (Tango) { private static Node opCall (InternalNode node) { Node proxy; proxy.node = node; return proxy; } } else { private bool shouldAddToDoc = true; private bool isRoot = true; private static Node opCall (InternalNode node, bool shouldAddToDoc = false, bool isRoot = false) { Node proxy; proxy.node = node; proxy.shouldAddToDoc = shouldAddToDoc; proxy.isRoot = isRoot; return proxy; } } public static Node invalid () { return Node(null); } tstring name () { return node.name; } tstring value () { return node.value; } Node parent () { return Node(node.parent); } bool isValid () { return node !is null; } VisitorProxy children () { return VisitorProxy(node.children); } VisitorProxy attributes () { return VisitorProxy(node.attributes); } QueryProxy query () { return QueryProxy(node.query); } Node element (tstring name, tstring value = null) { version (Tango) return Node(node.element(null, name, value)); else { auto element = new Element(name, value); if (isRoot) { node.tag = element.tag; node ~= new Text(value); return Node(node, true, false); } else { if (shouldAddToDoc) { shouldAddToDoc = false; node ~= element; } else node ~= element; return Node(element, shouldAddToDoc, false); } } } Node attribute (tstring name, tstring value) { node.attribute(null, name, value); version (Tango) return *this; else return this; } void attach (Node node) { version (Tango) this.node.move(node.node); else this.node.elements ~= node.node; } } struct QueryProxy { version (Tango) { private QueryNode node; private bool delegate (Node) currentFilter; } version (Phobos) private Node[] nodes_; private static QueryProxy opCall (QueryNode node) { QueryProxy qp; version (Tango) qp.node = node; else qp.nodes_ = [Node(node)]; return qp; } version (Phobos) { private static QueryProxy opCall (Node[] nodes) { QueryProxy qp; qp.nodes_ = nodes; return qp; } } version (Tango) { private bool internalFilter (InternalNode node) { return currentFilter(Node(node)); } } QueryProxy attribute (bool delegate (Node) filter) { version (Tango) { this.currentFilter = filter; return QueryProxy(node.attribute(&internalFilter)); } else { Node[] nodes; foreach (node ; nodes_) { foreach (attr ; node.attributes.nodes) { auto n = Node(attr); if (filter && filter(n)) nodes ~= n; } } return QueryProxy(nodes); } } QueryProxy attribute (tstring name = null) { version (Tango) return QueryProxy(node.attribute(name)); else { bool filter (Node node) { return node.name == name; } bool always (Node node) { return true; } if (name.length > 0) return attribute(&filter); return attribute(&always); } } Node[] nodes () { version (Tango) { auto proxies = new Node[node.nodes.length]; foreach (i, node ; node.nodes) proxies[i] = Node(node); return proxies; } else return nodes_; } QueryProxy opIndex (tstring query) { version (Tango) return QueryProxy(node[query]); else { Node[] proxies; foreach (parent ; nodes_) { if (parent.name == query) proxies ~= parent; foreach (e ; parent.node.elements) { if (e.tag.name == query) proxies ~= Node(e); } } return QueryProxy(proxies); } } int opApply (int delegate (ref Node) dg) { version (Tango) auto visitor = node; else auto visitor = nodes_; int result; foreach (n ; visitor) { version (Tango) { auto p = Node(n); result = dg(p); } else result = dg(n); if (result) break; } return result; } } /// bool strictErrorChecking; /// uint indentation = 4; private Doc doc; version (Tango) private DocPrinter!(T) printer; else InternalNode currentNode; this (bool strictErrorChecking = true) { version (Tango) doc = new Doc; else doc = new Doc(new Tag("root")); this.strictErrorChecking = strictErrorChecking; } XMLDocument header (tstring encoding = null) { version (Tango) doc.header(encoding); else { tstring newEncoding = encoding.length > 0 ? encoding : "UTF-8"; tstring header = `<?xml version="1.0" encoding="` ~ newEncoding ~ `"?>`; doc.prolog = header; } return this; } XMLDocument reset () { version (Tango) doc.reset; else doc = new Doc(new Tag("root")); return this; } Node tree () { version (Tango) return Node(doc.tree); else return Node(doc, true, true); } void parse (tstring xml) { version (Tango) doc.parse(xml); else doc = new Doc(xml); } QueryProxy query () { version (Tango) return QueryProxy(doc.tree.query); else return QueryProxy(doc); } string toString () { version (Tango) { if (!printer) printer = new DocPrinter!(T); printer.indent = indentation; return printer.print(doc); } else return doc.prolog ~ "\n" ~ join(doc.pretty(indentation), "\n"); } Node createNode (tstring name, tstring value = null) { version (Tango) return Node(tree.element(name, value).node.detach); else return Node(new Element(name, value), false, false); } }