001 // Copyright 2006, 2007 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry.dom;
016
017 import org.apache.tapestry.ioc.internal.util.Defense;
018
019 import java.io.PrintWriter;
020
021 /**
022 * The root node of a DOM.
023 */
024 public final class Document extends Node
025 {
026 private Element _rootElement;
027
028 private DTD _dtd;
029
030 private final MarkupModel _model;
031
032 private final String _encoding;
033
034 public Document(MarkupModel model)
035 {
036 this(model, null);
037 }
038
039 public Document(MarkupModel model, String encoding)
040 {
041 super(null);
042
043 _model = model;
044 _encoding = encoding;
045 }
046
047 Document getDocument()
048 {
049 return this;
050 }
051
052 /**
053 * Finds an element based on a path of element names.
054 *
055 * @param path slash separated series of element names
056 * @return the matching element, or null if not found
057 * @see Element#find(String)
058 */
059 public Element find(String path)
060 {
061 Defense.notBlank(path, "path");
062
063 if (_rootElement == null) return null;
064
065 int slashx = path.indexOf("/");
066
067 String rootElementName = slashx < 0 ? path : path.substring(0, slashx);
068
069 if (!_rootElement.getName().equals(rootElementName)) return null;
070
071 return slashx < 0 ? _rootElement : _rootElement.find(path.substring(slashx + 1));
072 }
073
074 /**
075 * Builds with an instance of {@link DefaultMarkupModel}.
076 */
077 public Document()
078 {
079 this(new DefaultMarkupModel());
080 }
081
082 public MarkupModel getMarkupModel()
083 {
084 return _model;
085 }
086
087 /**
088 * Creates the root element for this document, replacing any previous root element.
089 */
090 public Element newRootElement(String name)
091 {
092 _rootElement = new Element(this, null, name);
093
094 return _rootElement;
095 }
096
097 /**
098 * Creates a new root element within a namespace.
099 *
100 * @param namespace URI of namespace containing the element
101 * @param name name of element with namespace
102 * @return the root element
103 */
104 public Element newRootElement(String namespace, String name)
105 {
106 _rootElement = new Element(this, namespace, name);
107
108 return _rootElement;
109 }
110
111 @Override
112 public void toMarkup(PrintWriter writer)
113 {
114 if (_rootElement == null) throw new IllegalStateException(DomMessages.noRootElement());
115
116
117 if (_model.isXML())
118 {
119 writer.print("<?xml version=\"1.0\"");
120
121 if (_encoding != null) writer.printf(" encoding=\"%s\"", _encoding);
122
123 writer.print("?>\n");
124 }
125
126 // TODO: lead-in comments, directives.
127 if (_dtd != null)
128 {
129 _dtd.toMarkup(writer);
130 }
131
132 _rootElement.toMarkup(writer);
133 }
134
135 @Override
136 public String toString()
137 {
138 if (_rootElement == null) return "[empty Document]";
139
140 return super.toString();
141 }
142
143 public Element getRootElement()
144 {
145 return _rootElement;
146 }
147
148 /**
149 * Tries to find an element in this document whose id is specified.
150 *
151 * @param id the value of the id attribute of the element being looked for
152 * @return the element if found. null if not found.
153 */
154 public Element getElementById(String id)
155 {
156 return _rootElement.getElementById(id);
157 }
158
159 public void dtd(String name, String publicId, String systemId)
160 {
161 _dtd = new DTD(name, publicId, systemId);
162 }
163 }