/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.query.processor.xml; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; import javax.xml.transform.sax.TransformerHandler; import org.teiid.core.util.Assertion; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; class Element{ static final String DEFAULT_ATTRIBUTE_TYPE = "CDATA"; //$NON-NLS-1$ static final AttributesImpl EMPTY_ATTRIBUTES = new AttributesImpl(); private NodeDescriptor descriptor; private AttributesImpl attributes; private String content; private String comment; private boolean isOptional; private final boolean wasOptional; private boolean elementStarted; private boolean elementEnded; private Element parent; private List children = new LinkedList(); private NodeDescriptor nillableDescriptor; private TransformerHandler handler; Element(NodeDescriptor descripter, TransformerHandler handler){ this.descriptor = descripter; this.handler = handler; this.isOptional = descripter.isOptional(); this.wasOptional = descripter.isOptional(); } void setAttribute(NodeDescriptor descriptor, String value){ if (this.elementStarted) { Assertion.failed("Attributes must not be added to Element after Element is started."); //$NON-NLS-1$ } if(attributes == null) { attributes = new AttributesImpl(); } attributes.addAttribute(descriptor.getNamespaceURI(), descriptor.getName(), descriptor.getQName(), DEFAULT_ATTRIBUTE_TYPE, value); } void setParent(Element parent){ this.parent = parent; } Element getParent(){ return this.parent; } void startElement() throws SAXException { if(elementStarted){ return; } //start namespace prefix mapping Properties namespaceURIs = descriptor.getNamespaceURIs(); if(namespaceURIs != null){ Iterator iter = namespaceURIs.entrySet().iterator(); while(iter.hasNext()){ Map.Entry namespaceURI = (Map.Entry)iter.next(); String prefix = (String)namespaceURI.getKey(); String uri = (String)namespaceURI.getValue(); //start name space mapping if not started //by its parent yet if(parent != null && uri.equals(parent.getNamespaceURI(prefix))) { continue; } if(uri.length() > 0) { handler.startPrefixMapping(prefix, uri); } } } //start and output element with its attributes if(attributes == null) { attributes = EMPTY_ATTRIBUTES; } handler.startElement(descriptor.getNamespaceURI(), descriptor.getName(), descriptor.getQName(), attributes); //output comment if(comment != null){ handler.comment(comment.toCharArray(),0, comment.length()); } //output content if(content != null){ handler.characters(content.toCharArray(),0, content.length()); } //we do not need attributes and content any more attributes = null; content = null; isOptional = false; elementStarted = true; } void setContent(String content){ this.content = content; } void endElement() throws SAXException{ if(elementEnded){ return; } //end element (output end tag) handler.endElement(descriptor.getNamespaceURI(), descriptor.getName(), descriptor.getQName()); //end namespace prefix mapping Properties namespaceURIs = descriptor.getNamespaceURIs(); if(namespaceURIs != null){ Iterator iter = namespaceURIs.entrySet().iterator(); while(iter.hasNext()){ Map.Entry namespaceURI = (Map.Entry)iter.next(); String prefix = (String)namespaceURI.getKey(); String uri = (String)namespaceURI.getValue(); if(parent != null && uri.equals(parent.getNamespaceURI(prefix))) { continue; } handler.endPrefixMapping(prefix); } } elementEnded = true; } void setComment(String comment){ if (this.elementStarted) { Assertion.failed("Comment must not be added to Element after Element is started."); //$NON-NLS-1$ } this.comment = comment; } String getNamespaceURI(String namespacePrefix){ Properties namespaceURIs = descriptor.getNamespaceURIs(); if(namespaceURIs != null) { String uri = (String)namespaceURIs.get(namespacePrefix); if(uri != null){ return uri; } } if(parent != null){ //look for namespace prefix in its parent return parent.getNamespaceURI(namespacePrefix); } return null; } boolean hadOptionalParent() { if (parent != null) { if (parent.wasOptional()) { return true; } return parent.hadOptionalParent(); } return false; } boolean isOptional() { return isOptional; } void setOptional(boolean b) { isOptional = b; } public String toString(){ return descriptor.getQName(); } boolean isChildOf(Element elementToRemove) { boolean isChild = false; Element parentObj = parent; while(parentObj != null){ if(parentObj == elementToRemove){ isChild = true; break; } parentObj = parentObj.getParent(); } return isChild; } /** * @return Returns the nillableDescriptor. * @since 5.0 */ public NodeDescriptor getNillableDescriptor() { return this.nillableDescriptor; } /** * @param nillableDescriptor The nillableDescriptor to set. * @since 5.0 */ public void setNillableDescriptor(NodeDescriptor nillableDescriptor) { this.nillableDescriptor = nillableDescriptor; } /** * @return Returns the elementStarted. * @since 5.0 */ public boolean isElementStarted() { return this.elementStarted; } /** * @return Returns the children. * @since 5.0 */ public List getChildren() { return this.children; } public void addChild(Element child) { this.children.add(child); } /** * @return Returns the wasOptional. * @since 5.0 */ public boolean wasOptional() { return this.wasOptional; } }