001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.xml.impl;
017:
018: import java.util.ArrayList;
019: import java.util.List;
020: import java.util.logging.Level;
021: import java.util.logging.Logger;
022:
023: import javax.xml.namespace.QName;
024:
025: import org.eclipse.xsd.XSDAttributeDeclaration;
026: import org.eclipse.xsd.XSDElementDeclaration;
027: import org.eclipse.xsd.XSDFactory;
028: import org.eclipse.xsd.XSDSchemaContent;
029: import org.eclipse.xsd.XSDSimpleTypeDefinition;
030: import org.eclipse.xsd.XSDTypeDefinition;
031: import org.eclipse.xsd.util.XSDConstants;
032: import org.eclipse.xsd.util.XSDUtil;
033: import org.geotools.xml.AttributeInstance;
034: import org.geotools.xml.Binding;
035: import org.geotools.xml.ElementInstance;
036: import org.geotools.xml.InstanceComponent;
037: import org.geotools.xml.Node;
038: import org.geotools.xml.Parser;
039: import org.geotools.xml.SchemaIndex;
040: import org.geotools.xml.Schemas;
041: import org.picocontainer.defaults.DefaultPicoContainer;
042: import org.xml.sax.Attributes;
043: import org.xml.sax.SAXException;
044:
045: public class ElementHandlerImpl extends HandlerImpl implements
046: ElementHandler {
047: /** parent handler **/
048: Handler parent;
049:
050: /** the element declaration **/
051: XSDElementDeclaration content;
052:
053: /** the element instance **/
054: ElementImpl element;
055:
056: /** the running parser */
057: ParserHandler parser;
058:
059: /** the element type strategy **/
060: Binding strategy;
061:
062: /** child handlers **/
063: //ArrayList childHandlers;
064: /** parse tree for the element **/
065: NodeImpl node;
066:
067: /** parsed value **/
068: Object value;
069:
070: public ElementHandlerImpl(XSDElementDeclaration content,
071: Handler parent, ParserHandler parser) {
072: this .content = content;
073: this .parent = parent;
074: this .parser = parser;
075:
076: //childHandlers = new ArrayList();
077: }
078:
079: public void startElement(QName qName, Attributes attributes)
080: throws SAXException {
081: //clear handler list
082: //childHandlers.clear();
083:
084: //create the attributes
085: List atts = new ArrayList();
086:
087: for (int i = 0; i < attributes.getLength(); i++) {
088: String rawAttQName = attributes.getQName(i);
089: if (rawAttQName != null) {
090: //ignore namespace declarations
091: if (rawAttQName.startsWith("xmlns:")) {
092: continue;
093: }
094: //ignore xsi:schemaLocation
095: if (rawAttQName.endsWith("schemaLocation")) {
096: String prefix = "";
097: if (rawAttQName.indexOf(':') != -1) {
098: prefix = rawAttQName.substring(0, rawAttQName
099: .indexOf(':'));
100: }
101:
102: String uri = parser.getNamespaceSupport().getURI(
103: prefix);
104: if (uri != null
105: && uri
106: .equals(XSDConstants.SCHEMA_INSTANCE_URI_2001)) {
107: continue;
108: }
109: }
110: }
111: // String qName = attributes.getQName(i);
112: //
113: //
114: // //ignore schema location attribute
115: // if ( attributes.getQName(i) != null && attributes.getQName(index))
116: //
117: String uri = attributes.getURI(i);
118: String name = attributes.getLocalName(i);
119:
120: QName attQName = new QName(uri, name);
121:
122: XSDAttributeDeclaration decl = Schemas
123: .getAttributeDeclaration(content, attQName);
124:
125: if (decl == null) {
126: //check wether unknown attributes should be parsed
127: if (!parser.isStrict()) {
128: if (parser.getLogger().isLoggable(Level.FINE))
129: parser.getLogger().fine(
130: "Parsing unknown attribute: "
131: + attQName);
132:
133: //create a mock attribute and continue
134: decl = XSDFactory.eINSTANCE
135: .createXSDAttributeDeclaration();
136: decl.setName(attQName.getLocalPart());
137: decl.setTargetNamespace(attQName.getNamespaceURI());
138:
139: //set the type to be of string
140: XSDSimpleTypeDefinition type = (XSDSimpleTypeDefinition) XSDUtil
141: .getSchemaForSchema(
142: XSDUtil.SCHEMA_FOR_SCHEMA_URI_2001)
143: .getSimpleTypeIdMap().get("string");
144:
145: decl.setTypeDefinition(type);
146: }
147: }
148:
149: //TODO: validate, if there is no declaration for an attribute, then
150: //TODO: make sure no required attributes are missing
151: // validation should fail, this is being side stepped for now until
152: // a good way of handling the namespace attributes on the root
153: // element, for now we just ignore attributes we dont find in the
154: // schema
155: if (decl != null) {
156: AttributeInstance att = new AttributeImpl(decl);
157: att.setNamespace(decl.getTargetNamespace());
158: att.setName(decl.getName());
159: att.setText(attributes.getValue(i));
160:
161: atts.add(att);
162: } else {
163: parser.getLogger().warning(
164: "Could not find attribute declaration: "
165: + attQName);
166: }
167: }
168:
169: //create the element
170: element = new ElementImpl(content);
171: element.setNamespace(qName.getNamespaceURI());
172: element.setName(qName.getLocalPart());
173: element.setAttributes((AttributeInstance[]) atts
174: .toArray(new AttributeInstance[atts.size()]));
175:
176: //create the parse tree for the node
177: node = new NodeImpl(element);
178:
179: //parse the attributes
180: for (int i = 0; i < element.getAttributes().length; i++) {
181: AttributeInstance attribute = element.getAttributes()[i];
182: ParseExecutor executor = new ParseExecutor(attribute, null,
183: parent.getContext(), parser);
184:
185: parser.getBindingWalker().walk(
186: attribute.getAttributeDeclaration(), executor,
187: parent.getContext());
188:
189: Object parsed = executor.getValue();
190: node.addAttribute(new NodeImpl(attribute, parsed));
191: }
192:
193: //create context for children
194: //TODO: this should only be done if the element is complex, this class
195: // needs to be split into two, one for complex, other for simple
196: setContext(new DefaultPicoContainer(parent.getContext()));
197:
198: //set the context on the binding factory
199: ((BindingFactoryImpl) parser.getBindingFactory())
200: .setContext(getContext());
201:
202: //"start" the child handler
203: parent.startChildHandler(this );
204:
205: // ContextInitializer initer = new ContextInitializer(element, node,
206: // getContext());
207: // parser.getBindingWalker().walk(element .getElementDeclaration(), initer, getContext() );
208: }
209:
210: public void characters(char[] ch, int start, int length)
211: throws SAXException {
212: //simply add the text to the element
213: element.addText(ch, start, length);
214: }
215:
216: public void endElement(QName qName) throws SAXException {
217: //round up the children
218: // for (int i = 0; i < childHandlers.size(); i++) {
219: // Handler handler = (Handler) childHandlers.get(i);
220: // node.addChild(new NodeImpl(handler.getComponent(),
221: // handler.getValue()));
222: // }
223:
224: //get the containing type
225: XSDTypeDefinition container = null;
226: if (getParentHandler().getComponent() != null) {
227: container = getParentHandler().getComponent()
228: .getTypeDefinition();
229: }
230: ParseExecutor executor = new ParseExecutor(element, node,
231: getParentHandler().getContext(), parser);
232: parser.getBindingWalker().walk(element.getElementDeclaration(),
233: executor, container, getParentHandler().getContext());
234:
235: //cache the parsed value
236: value = executor.getValue();
237:
238: if (value == null) {
239: //TODO: instead of continuuing, just remove the element from
240: // the parent, or figure out if the element is 'optional' and
241: // remove
242: if (parser.getLogger().isLoggable(Level.FINE))
243: parser.getLogger().fine(
244: "Binding for " + element.getName()
245: + " returned null");
246: }
247:
248: //set the value for this node in the parse tree
249: node.setValue(value);
250:
251: //end this child handler
252: parent.endChildHandler(this );
253:
254: //kill the context
255: parent.getContext().removeChildContainer(getContext());
256: }
257:
258: public Handler createChildHandler(QName qName) {
259: return getChildHandlerInternal(qName);
260: }
261:
262: private Handler getChildHandlerInternal(QName qName) {
263: SchemaIndex index = parser.getSchemaIndex();
264:
265: XSDElementDeclaration element = index.getChildElement(content,
266: qName);
267:
268: if (element != null) {
269: //TODO: determine wether the element is complex or simple, and create
270: ElementHandler handler = parser.getHandlerFactory()
271: .createElementHandler(element, this , parser);
272:
273: return handler;
274: }
275:
276: //could not find the element as a direct child of the parent, check
277: // for a global element, and then check its substituation group
278: element = index.getElementDeclaration(qName);
279: if (element != null) {
280: XSDElementDeclaration sub = element
281: .getSubstitutionGroupAffiliation();
282:
283: if (sub != null) {
284: QName subQName = new QName(sub.getTargetNamespace(),
285: sub.getName());
286: Handler handler = getChildHandlerInternal(subQName);
287:
288: if (handler != null) {
289: //this means that hte element is substituatable for an
290: // actual child. now we have have choice, do we return
291: // a handler for the actual element, or the element it
292: // substituable for - the answer is to check the bindings
293: //TODO: ask the binding
294:
295: handler = parser
296: .getHandlerFactory()
297: .createElementHandler(element, this , parser);
298:
299: return handler;
300: }
301: }
302: }
303:
304: //if
305: return null;
306: }
307:
308: // public List getChildHandlers() {
309: // return childHandlers;
310: // }
311:
312: public void startChildHandler(Handler child) {
313: //childHandlers.add(child);
314: node.addChild(child.getParseNode());
315:
316: //initialize the context for the handler
317: if (child instanceof ElementHandler) {
318: ElementInstance childInstance = (ElementInstance) child
319: .getComponent();
320: ContextInitializer initer = new ContextInitializer(
321: childInstance, node, child.getContext());
322: parser.getBindingWalker().walk(
323: element.getElementDeclaration(), initer,
324: getContext());
325: }
326: }
327:
328: public void endChildHandler(Handler child) {
329: //add the node to the parse tree
330: //childHandlers.remove(child);
331: }
332:
333: public Handler getParentHandler() {
334: return parent;
335: }
336:
337: public XSDSchemaContent getSchemaContent() {
338: return content;
339: }
340:
341: public Node getParseNode() {
342: return node;
343: }
344:
345: public XSDElementDeclaration getElementDeclaration() {
346: return content;
347: }
348:
349: public InstanceComponent getComponent() {
350: return element;
351: }
352:
353: public void setComponent(ElementImpl element) {
354: this .element = element;
355: }
356:
357: public Object getValue() {
358: return value;
359: }
360:
361: public String toString() {
362: return (node != null) ? node.toString() : "";
363: }
364: }
|