001: package net.sf.saxon.xom;
002:
003: import net.sf.saxon.Configuration;
004: import net.sf.saxon.om.DocumentInfo;
005: import net.sf.saxon.om.NamePool;
006: import net.sf.saxon.om.NodeInfo;
007: import net.sf.saxon.type.Type;
008: import nu.xom.Attribute;
009: import nu.xom.Document;
010: import nu.xom.Element;
011: import nu.xom.Node;
012:
013: import java.util.HashMap;
014:
015: /**
016: * The root node of an XPath tree. (Or equivalently, the tree itself).
017: * <P>
018: * This class is used not only for a document, but also for the root
019: * of a document-less tree fragment.
020: *
021: * @author Michael H. Kay
022: * @author Wolfgang Hoschek (ported net.sf.saxon.jdom to XOM)
023: */
024:
025: public class DocumentWrapper extends NodeWrapper implements
026: DocumentInfo {
027:
028: protected Configuration config;
029:
030: protected String baseURI;
031:
032: protected int documentNumber;
033:
034: private HashMap idIndex;
035:
036: /**
037: * Create a Saxon wrapper for a XOM root node
038: *
039: * @param root
040: * The XOM root node
041: * @param baseURI
042: * The base URI for all the nodes in the tree
043: * @param config
044: * The configuration which defines the name pool used for all
045: * names in this tree
046: */
047: public DocumentWrapper(Node root, String baseURI,
048: Configuration config) {
049: super (root, null, 0);
050: if (root.getParent() != null)
051: throw new IllegalArgumentException(
052: "root node must not have a parent node");
053: this .baseURI = baseURI;
054: this .docWrapper = this ;
055: setConfiguration(config);
056: }
057:
058: /**
059: * Wrap a node in the XOM document.
060: *
061: * @param node
062: * The node to be wrapped. This must be a node in the same
063: * document (the system does not check for this).
064: * @return the wrapping NodeInfo object
065: */
066:
067: public NodeInfo wrap(Node node) {
068: if (node == this .node) {
069: return this ;
070: }
071: return makeWrapper(node, this );
072: }
073:
074: /**
075: * Set the configuration, which defines the name pool used for all names in
076: * this document. This is always called after a new document has been
077: * created. The implementation must register the name pool with the
078: * document, so that it can be retrieved using getNamePool(). It must also
079: * call NamePool.allocateDocumentNumber(), and return the relevant document
080: * number when getDocumentNumber() is subsequently called.
081: *
082: * @param config
083: * The configuration to be used
084: */
085:
086: public void setConfiguration(Configuration config) {
087: this .config = config;
088: this .documentNumber = config.getDocumentNumberAllocator()
089: .allocateDocumentNumber();
090: }
091:
092: /**
093: * Get the configuration previously set using setConfiguration
094: */
095:
096: public Configuration getConfiguration() {
097: return config;
098: }
099:
100: /**
101: * Get the name pool used for the names in this document
102: *
103: * @return the name pool in which all the names used in this document are
104: * registered
105: */
106:
107: public NamePool getNamePool() {
108: return config.getNamePool();
109: }
110:
111: /**
112: * Get the unique document number for this document (the number is unique
113: * for all documents within a NamePool)
114: *
115: * @return the unique number identifying this document within the name pool
116: */
117:
118: public int getDocumentNumber() {
119: return documentNumber;
120: }
121:
122: /**
123: * Get the element with a given ID, if any
124: *
125: * @param id
126: * the required ID value
127: * @return the element with the given ID, or null if there is no such ID
128: * present (or if the parser has not notified attributes as being of
129: * type ID).
130: */
131:
132: public NodeInfo selectID(String id) {
133: if (idIndex == null) {
134: Element elem;
135: switch (nodeKind) {
136: case Type.DOCUMENT:
137: elem = ((Document) node).getRootElement();
138: break;
139: case Type.ELEMENT:
140: elem = (Element) node;
141: break;
142: default:
143: return null;
144: }
145: idIndex = new HashMap(50);
146: buildIDIndex(elem);
147: }
148: return (NodeInfo) idIndex.get(id);
149: }
150:
151: private void buildIDIndex(Element elem) {
152: // walk the tree in reverse document order, to satisfy the XPath 1.0 rule
153: // that says if an ID appears twice, the first one wins
154: for (int i = elem.getChildCount(); --i >= 0;) {
155: Node child = elem.getChild(i);
156: if (child instanceof Element) {
157: buildIDIndex((Element) child);
158: }
159: }
160: for (int i = elem.getAttributeCount(); --i >= 0;) {
161: Attribute att = elem.getAttribute(i);
162: if (att.getType() == Attribute.Type.ID) {
163: idIndex.put(att.getValue(), wrap(elem));
164: }
165: }
166: }
167:
168: /**
169: * Get the unparsed entity with a given name
170: *
171: * @param name
172: * the name of the entity
173: * @return null: XOM does not provide access to unparsed entities
174: * @return if the entity exists, return an array of two Strings, the first
175: * holding the system ID of the entity, the second holding the
176: * public ID if there is one, or null if not. If the entity does not
177: * exist, return null.
178: */
179:
180: public String[] getUnparsedEntity(String name) {
181: return null;
182: }
183:
184: }
185:
186: //
187: // The contents of this file are subject to the Mozilla Public License Version
188: // 1.0 (the "License");
189: // you may not use this file except in compliance with the License. You may
190: // obtain a copy of the
191: // License at http://www.mozilla.org/MPL/
192: //
193: // Software distributed under the License is distributed on an "AS IS" basis,
194: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
195: // See the License for the specific language governing rights and limitations
196: // under the License.
197: //
198: // The Original Code is: all this file.
199: //
200: // The Initial Developer of the Original Code is Michael Kay
201: //
202: // Portions created by (your name) are Copyright (C) (your legal entity). All
203: // Rights Reserved.
204: //
205: // Contributor(s): none.
206: //
|