| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /* |
| * $Id$ |
| */ |
| package org.apache.xml.serializer; |
| |
| import java.io.IOException; |
| import java.util.HashMap; |
| import java.util.Set; |
| |
| import javax.xml.transform.OutputKeys; |
| import javax.xml.transform.SourceLocator; |
| import javax.xml.transform.Transformer; |
| |
| import org.apache.xml.serializer.utils.MsgKey; |
| import org.apache.xml.serializer.utils.Utils; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.Locator; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXParseException; |
| |
| |
| /** |
| * This class acts as a base class for the XML "serializers" |
| * and the stream serializers. |
| * It contains a number of common fields and methods. |
| * |
| * @xsl.usage internal |
| */ |
| public abstract class SerializerBase |
| implements SerializationHandler, SerializerConstants |
| { |
| SerializerBase() { |
| return; |
| } |
| |
| /** |
| * The name of the package that this class is in. |
| * <p> |
| * Not a public API. |
| */ |
| public static final String PKG_NAME; |
| |
| /** |
| * The same as the name of the package that this class is in |
| * except that '.' are replaced with '/'. |
| * <p> |
| * Not a public API. |
| */ |
| public static final String PKG_PATH; |
| |
| static { |
| String fullyQualifiedName = SerializerBase.class.getName(); |
| int lastDot = fullyQualifiedName.lastIndexOf('.'); |
| if (lastDot < 0) { |
| PKG_NAME = ""; |
| } else { |
| PKG_NAME = fullyQualifiedName.substring(0, lastDot); |
| } |
| |
| StringBuffer sb = new StringBuffer(); |
| for (int i = 0; i < PKG_NAME.length(); i++) { |
| char ch = PKG_NAME.charAt(i); |
| if (ch == '.') |
| sb.append('/'); |
| else |
| sb.append(ch); |
| } |
| PKG_PATH = sb.toString(); |
| } |
| |
| |
| |
| /** |
| * To fire off the end element trace event |
| * @param name Name of element |
| */ |
| protected void fireEndElem(String name) |
| throws org.xml.sax.SAXException |
| { |
| if (m_tracer != null) |
| { |
| flushMyWriter(); |
| m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENDELEMENT,name, (Attributes)null); |
| } |
| } |
| |
| /** |
| * Report the characters trace event |
| * @param chars content of characters |
| * @param start starting index of characters to output |
| * @param length number of characters to output |
| */ |
| protected void fireCharEvent(char[] chars, int start, int length) |
| throws org.xml.sax.SAXException |
| { |
| if (m_tracer != null) |
| { |
| flushMyWriter(); |
| m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_CHARACTERS, chars, start,length); |
| } |
| } |
| |
| /** |
| * true if we still need to call startDocumentInternal() |
| */ |
| protected boolean m_needToCallStartDocument = true; |
| |
| /** True if a trailing "]]>" still needs to be written to be |
| * written out. Used to merge adjacent CDATA sections |
| */ |
| protected boolean m_cdataTagOpen = false; |
| |
| /** |
| * All the attributes of the current element, collected from |
| * startPrefixMapping() calls, or addAddtribute() calls, or |
| * from the SAX attributes in a startElement() call. |
| */ |
| protected AttributesImplSerializer m_attributes = new AttributesImplSerializer(); |
| |
| /** |
| * Tells if we're in an EntityRef event. |
| */ |
| protected boolean m_inEntityRef = false; |
| |
| /** This flag is set while receiving events from the external DTD */ |
| protected boolean m_inExternalDTD = false; |
| |
| /** |
| * The System ID for the doc type. |
| */ |
| protected String m_doctypeSystem; |
| |
| /** |
| * The public ID for the doc type. |
| */ |
| protected String m_doctypePublic; |
| |
| /** |
| * Flag to tell that we need to add the doctype decl, which we can't do |
| * until the first element is encountered. |
| */ |
| boolean m_needToOutputDocTypeDecl = true; |
| |
| /** |
| * Tells if we should write the XML declaration. |
| */ |
| protected boolean m_shouldNotWriteXMLHeader = false; |
| |
| /** |
| * The standalone value for the doctype. |
| */ |
| private String m_standalone; |
| |
| /** |
| * True if standalone was specified. |
| */ |
| protected boolean m_standaloneWasSpecified = false; |
| |
| /** |
| * Flag to tell if indenting (pretty-printing) is on. |
| */ |
| protected boolean m_doIndent = false; |
| /** |
| * Amount to indent. |
| */ |
| protected int m_indentAmount = 0; |
| |
| /** |
| * Tells the XML version, for writing out to the XML decl. |
| */ |
| protected String m_version = null; |
| |
| /** |
| * The mediatype. Not used right now. |
| */ |
| protected String m_mediatype; |
| |
| /** |
| * The transformer that was around when this output handler was created (if |
| * any). |
| */ |
| private Transformer m_transformer; |
| |
| /** |
| * Namespace support, that keeps track of currently defined |
| * prefix/uri mappings. As processed elements come and go, so do |
| * the associated mappings for that element. |
| */ |
| protected NamespaceMappings m_prefixMap; |
| |
| /** |
| * Handle for firing generate events. This interface may be implemented |
| * by the referenced transformer object. |
| */ |
| protected SerializerTrace m_tracer; |
| |
| protected SourceLocator m_sourceLocator; |
| |
| |
| /** |
| * The writer to send output to. This field is only used in the ToStream |
| * serializers, but exists here just so that the fireStartDoc() and |
| * other fire... methods can flush this writer when tracing. |
| */ |
| protected java.io.Writer m_writer = null; |
| |
| /** |
| * A reference to "stack frame" corresponding to |
| * the current element. Such a frame is pushed at a startElement() |
| * and popped at an endElement(). This frame contains information about |
| * the element, such as its namespace URI. |
| */ |
| protected ElemContext m_elemContext = new ElemContext(); |
| |
| /** |
| * A utility buffer for converting Strings passed to |
| * character() methods to character arrays. |
| * Reusing this buffer means not creating a new character array |
| * everytime and it runs faster. |
| */ |
| protected char[] m_charsBuff = new char[60]; |
| |
| /** |
| * A utility buffer for converting Strings passed to |
| * attribute methods to character arrays. |
| * Reusing this buffer means not creating a new character array |
| * everytime and it runs faster. |
| */ |
| protected char[] m_attrBuff = new char[30]; |
| |
| /** |
| * Receive notification of a comment. |
| * |
| * @see ExtendedLexicalHandler#comment(String) |
| */ |
| public void comment(String data) throws SAXException |
| { |
| m_docIsEmpty = false; |
| |
| final int length = data.length(); |
| if (length > m_charsBuff.length) |
| { |
| m_charsBuff = new char[length * 2 + 1]; |
| } |
| data.getChars(0, length, m_charsBuff, 0); |
| comment(m_charsBuff, 0, length); |
| } |
| |
| /** |
| * If at runtime, when the qname of the attribute is |
| * known, another prefix is specified for the attribute, then we can |
| * patch or hack the name with this method. For |
| * a qname of the form "ns?:otherprefix:name", this function patches the |
| * qname by simply ignoring "otherprefix". |
| * TODO: This method is a HACK! We do not have access to the |
| * XML file, it sometimes generates a NS prefix of the form "ns?" for |
| * an attribute. |
| */ |
| protected String patchName(String qname) |
| { |
| |
| |
| final int lastColon = qname.lastIndexOf(':'); |
| |
| if (lastColon > 0) { |
| final int firstColon = qname.indexOf(':'); |
| final String prefix = qname.substring(0, firstColon); |
| final String localName = qname.substring(lastColon + 1); |
| |
| // If uri is "" then ignore prefix |
| final String uri = m_prefixMap.lookupNamespace(prefix); |
| if (uri != null && uri.length() == 0) { |
| return localName; |
| } |
| else if (firstColon != lastColon) { |
| return prefix + ':' + localName; |
| } |
| } |
| return qname; |
| } |
| |
| /** |
| * Returns the local name of a qualified name. If the name has no prefix, |
| * then it works as the identity (SAX2). |
| * @param qname the qualified name |
| * @return the name, but excluding any prefix and colon. |
| */ |
| protected static String getLocalName(String qname) |
| { |
| final int col = qname.lastIndexOf(':'); |
| return (col > 0) ? qname.substring(col + 1) : qname; |
| } |
| |
| /** |
| * Receive an object for locating the origin of SAX document events. |
| * |
| * @param locator An object that can return the location of any SAX document |
| * event. |
| * |
| * Receive an object for locating the origin of SAX document events. |
| * |
| * <p>SAX parsers are strongly encouraged (though not absolutely |
| * required) to supply a locator: if it does so, it must supply |
| * the locator to the application by invoking this method before |
| * invoking any of the other methods in the DocumentHandler |
| * interface.</p> |
| * |
| * <p>The locator allows the application to determine the end |
| * position of any document-related event, even if the parser is |
| * not reporting an error. Typically, the application will |
| * use this information for reporting its own errors (such as |
| * character content that does not match an application's |
| * business rules). The information returned by the locator |
| * is probably not sufficient for use with a search engine.</p> |
| * |
| * <p>Note that the locator will return correct information only |
| * during the invocation of the events in this interface. The |
| * application should not attempt to use it at any other time.</p> |
| */ |
| public void setDocumentLocator(Locator locator) |
| { |
| return; |
| |
| // I don't do anything with this yet. |
| } |
| |
| /** |
| * Adds the given attribute to the set of collected attributes , but only if |
| * there is a currently open element. |
| * |
| * An element is currently open if a startElement() notification has |
| * occured but the start of the element has not yet been written to the |
| * output. In the stream case this means that we have not yet been forced |
| * to close the elements opening tag by another notification, such as a |
| * character notification. |
| * |
| * @param uri the URI of the attribute |
| * @param localName the local name of the attribute |
| * @param rawName the qualified name of the attribute |
| * @param type the type of the attribute (probably CDATA) |
| * @param value the value of the attribute |
| * @param XSLAttribute true if this attribute is coming from an xsl:attriute element |
| * @see ExtendedContentHandler#addAttribute(String, String, String, String, String) |
| */ |
| public void addAttribute( |
| String uri, |
| String localName, |
| String rawName, |
| String type, |
| String value, |
| boolean XSLAttribute) |
| throws SAXException |
| { |
| if (m_elemContext.m_startTagOpen) |
| { |
| addAttributeAlways(uri, localName, rawName, type, value, XSLAttribute); |
| } |
| |
| } |
| |
| /** |
| * Adds the given attribute to the set of attributes, even if there is |
| * no currently open element. This is useful if a SAX startPrefixMapping() |
| * should need to add an attribute before the element name is seen. |
| * |
| * @param uri the URI of the attribute |
| * @param localName the local name of the attribute |
| * @param rawName the qualified name of the attribute |
| * @param type the type of the attribute (probably CDATA) |
| * @param value the value of the attribute |
| * @param XSLAttribute true if this attribute is coming from an xsl:attribute element |
| * @return true if the attribute was added, |
| * false if an existing value was replaced. |
| */ |
| public boolean addAttributeAlways( |
| String uri, |
| String localName, |
| String rawName, |
| String type, |
| String value, |
| boolean XSLAttribute) |
| { |
| boolean was_added; |
| // final int index = |
| // (localName == null || uri == null) ? |
| // m_attributes.getIndex(rawName):m_attributes.getIndex(uri, localName); |
| int index; |
| // if (localName == null || uri == null){ |
| // index = m_attributes.getIndex(rawName); |
| // } |
| // else { |
| // index = m_attributes.getIndex(uri, localName); |
| // } |
| if (localName == null || uri == null || uri.length() == 0) |
| index = m_attributes.getIndex(rawName); |
| else { |
| index = m_attributes.getIndex(uri,localName); |
| } |
| if (index >= 0) |
| { |
| /* We've seen the attribute before. |
| * We may have a null uri or localName, but all |
| * we really want to re-set is the value anyway. |
| */ |
| m_attributes.setValue(index,value); |
| was_added = false; |
| } |
| else |
| { |
| // the attribute doesn't exist yet, create it |
| m_attributes.addAttribute(uri, localName, rawName, type, value); |
| was_added = true; |
| } |
| return was_added; |
| |
| } |
| |
| |
| /** |
| * Adds the given attribute to the set of collected attributes, |
| * but only if there is a currently open element. |
| * |
| * @param name the attribute's qualified name |
| * @param value the value of the attribute |
| */ |
| public void addAttribute(String name, final String value) |
| { |
| if (m_elemContext.m_startTagOpen) |
| { |
| final String patchedName = patchName(name); |
| final String localName = getLocalName(patchedName); |
| final String uri = getNamespaceURI(patchedName, false); |
| |
| addAttributeAlways(uri,localName, patchedName, "CDATA", value, false); |
| } |
| } |
| |
| /** |
| * Adds the given xsl:attribute to the set of collected attributes, |
| * but only if there is a currently open element. |
| * |
| * @param name the attribute's qualified name (prefix:localName) |
| * @param value the value of the attribute |
| * @param uri the URI that the prefix of the name points to |
| */ |
| public void addXSLAttribute(String name, final String value, final String uri) |
| { |
| if (m_elemContext.m_startTagOpen) |
| { |
| final String patchedName = patchName(name); |
| final String localName = getLocalName(patchedName); |
| |
| addAttributeAlways(uri,localName, patchedName, "CDATA", value, true); |
| } |
| } |
| |
| /** |
| * Add the given attributes to the currently collected ones. These |
| * attributes are always added, regardless of whether on not an element |
| * is currently open. |
| * @param atts List of attributes to add to this list |
| */ |
| public void addAttributes(Attributes atts) throws SAXException |
| { |
| |
| int nAtts = atts.getLength(); |
| |
| for (int i = 0; i < nAtts; i++) |
| { |
| String uri = atts.getURI(i); |
| |
| if (null == uri) |
| uri = ""; |
| |
| addAttributeAlways( |
| uri, |
| atts.getLocalName(i), |
| atts.getQName(i), |
| atts.getType(i), |
| atts.getValue(i), |
| false); |
| |
| } |
| } |
| |
| /** |
| * Return a {@link ContentHandler} interface into this serializer. |
| * If the serializer does not support the {@link ContentHandler} |
| * interface, it should return null. |
| * |
| * @return A {@link ContentHandler} interface into this serializer, |
| * or null if the serializer is not SAX 2 capable |
| * @throws IOException An I/O exception occured |
| */ |
| public ContentHandler asContentHandler() throws IOException |
| { |
| return this; |
| } |
| |
| /** |
| * Report the end of an entity. |
| * |
| * @param name The name of the entity that is ending. |
| * @throws org.xml.sax.SAXException The application may raise an exception. |
| * @see #startEntity |
| */ |
| public void endEntity(String name) throws org.xml.sax.SAXException |
| { |
| if (name.equals("[dtd]")) |
| m_inExternalDTD = false; |
| m_inEntityRef = false; |
| |
| if (m_tracer != null) |
| this.fireEndEntity(name); |
| } |
| |
| /** |
| * Flush and close the underlying java.io.Writer. This method applies to |
| * ToStream serializers, not ToSAXHandler serializers. |
| * @see ToStream |
| */ |
| public void close() |
| { |
| // do nothing (base behavior) |
| } |
| |
| /** |
| * Initialize global variables |
| */ |
| protected void initCDATA() |
| { |
| // CDATA stack |
| // _cdataStack = new Stack(); |
| // _cdataStack.push(new Integer(-1)); // push dummy value |
| } |
| |
| /** |
| * Returns the character encoding to be used in the output document. |
| * @return the character encoding to be used in the output document. |
| */ |
| public String getEncoding() |
| { |
| return getOutputProperty(OutputKeys.ENCODING); |
| } |
| |
| /** |
| * Sets the character encoding coming from the xsl:output encoding stylesheet attribute. |
| * @param m_encoding the character encoding |
| */ |
| public void setEncoding(String encoding) |
| { |
| setOutputProperty(OutputKeys.ENCODING,encoding); |
| } |
| |
| /** |
| * Sets the value coming from the xsl:output omit-xml-declaration stylesheet attribute |
| * @param b true if the XML declaration is to be omitted from the output |
| * document. |
| */ |
| public void setOmitXMLDeclaration(boolean b) |
| { |
| String val = b ? "yes":"no"; |
| setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,val); |
| } |
| |
| |
| /** |
| * @return true if the XML declaration is to be omitted from the output |
| * document. |
| */ |
| public boolean getOmitXMLDeclaration() |
| { |
| return m_shouldNotWriteXMLHeader; |
| } |
| |
| /** |
| * Returns the previously set value of the value to be used as the public |
| * identifier in the document type declaration (DTD). |
| * |
| *@return the public identifier to be used in the DOCTYPE declaration in the |
| * output document. |
| */ |
| public String getDoctypePublic() |
| { |
| return m_doctypePublic; |
| } |
| |
| /** Set the value coming from the xsl:output doctype-public stylesheet attribute. |
| * @param doctypePublic the public identifier to be used in the DOCTYPE |
| * declaration in the output document. |
| */ |
| public void setDoctypePublic(String doctypePublic) |
| { |
| setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, doctypePublic); |
| } |
| |
| |
| /** |
| * Returns the previously set value of the value to be used |
| * as the system identifier in the document type declaration (DTD). |
| * @return the system identifier to be used in the DOCTYPE declaration in |
| * the output document. |
| * |
| */ |
| public String getDoctypeSystem() |
| { |
| return m_doctypeSystem; |
| } |
| |
| /** Set the value coming from the xsl:output doctype-system stylesheet attribute. |
| * @param doctypeSystem the system identifier to be used in the DOCTYPE |
| * declaration in the output document. |
| */ |
| public void setDoctypeSystem(String doctypeSystem) |
| { |
| setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, doctypeSystem); |
| } |
| |
| /** Set the value coming from the xsl:output doctype-public and doctype-system stylesheet properties |
| * @param doctypeSystem the system identifier to be used in the DOCTYPE |
| * declaration in the output document. |
| * @param doctypePublic the public identifier to be used in the DOCTYPE |
| * declaration in the output document. |
| */ |
| public void setDoctype(String doctypeSystem, String doctypePublic) |
| { |
| setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, doctypeSystem); |
| setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, doctypePublic); |
| } |
| |
| /** |
| * Sets the value coming from the xsl:output standalone stylesheet attribute. |
| * @param standalone a value of "yes" indicates that the |
| * <code>standalone</code> delaration is to be included in the output |
| * document. This method remembers if the value was explicitly set using |
| * this method, verses if the value is the default value. |
| */ |
| public void setStandalone(String standalone) |
| { |
| setOutputProperty(OutputKeys.STANDALONE, standalone); |
| } |
| /** |
| * Sets the XSL standalone attribute, but does not remember if this is a |
| * default or explicite setting. |
| * @param standalone "yes" | "no" |
| */ |
| protected void setStandaloneInternal(String standalone) |
| { |
| if ("yes".equals(standalone)) |
| m_standalone = "yes"; |
| else |
| m_standalone = "no"; |
| |
| } |
| |
| /** |
| * Gets the XSL standalone attribute |
| * @return a value of "yes" if the <code>standalone</code> delaration is to |
| * be included in the output document. |
| * @see XSLOutputAttributes#getStandalone() |
| */ |
| public String getStandalone() |
| { |
| return m_standalone; |
| } |
| |
| /** |
| * @return true if the output document should be indented to visually |
| * indicate its structure. |
| */ |
| public boolean getIndent() |
| { |
| return m_doIndent; |
| } |
| /** |
| * Gets the mediatype the media-type or MIME type associated with the output |
| * document. |
| * @return the mediatype the media-type or MIME type associated with the |
| * output document. |
| */ |
| public String getMediaType() |
| { |
| return m_mediatype; |
| } |
| |
| /** |
| * Gets the version of the output format. |
| * @return the version of the output format. |
| */ |
| public String getVersion() |
| { |
| return m_version; |
| } |
| |
| /** |
| * Sets the value coming from the xsl:output version attribute. |
| * @param version the version of the output format. |
| * @see SerializationHandler#setVersion(String) |
| */ |
| public void setVersion(String version) |
| { |
| setOutputProperty(OutputKeys.VERSION, version); |
| } |
| |
| /** |
| * Sets the value coming from the xsl:output media-type stylesheet attribute. |
| * @param mediaType the non-null media-type or MIME type associated with the |
| * output document. |
| * @see javax.xml.transform.OutputKeys#MEDIA_TYPE |
| * @see SerializationHandler#setMediaType(String) |
| */ |
| public void setMediaType(String mediaType) |
| { |
| setOutputProperty(OutputKeys.MEDIA_TYPE,mediaType); |
| } |
| |
| /** |
| * @return the number of spaces to indent for each indentation level. |
| */ |
| public int getIndentAmount() |
| { |
| return m_indentAmount; |
| } |
| |
| /** |
| * Sets the indentation amount. |
| * @param m_indentAmount The m_indentAmount to set |
| */ |
| public void setIndentAmount(int m_indentAmount) |
| { |
| this.m_indentAmount = m_indentAmount; |
| } |
| |
| /** |
| * Sets the value coming from the xsl:output indent stylesheet |
| * attribute. |
| * @param doIndent true if the output document should be indented to |
| * visually indicate its structure. |
| * @see XSLOutputAttributes#setIndent(boolean) |
| */ |
| public void setIndent(boolean doIndent) |
| { |
| String val = doIndent ? "yes":"no"; |
| setOutputProperty(OutputKeys.INDENT,val); |
| } |
| |
| /** |
| * This method is used when a prefix/uri namespace mapping |
| * is indicated after the element was started with a |
| * startElement() and before and endElement(). |
| * startPrefixMapping(prefix,uri) would be used before the |
| * startElement() call. |
| * @param uri the URI of the namespace |
| * @param prefix the prefix associated with the given URI. |
| * |
| * @see ExtendedContentHandler#namespaceAfterStartElement(String, String) |
| */ |
| public void namespaceAfterStartElement(String uri, String prefix) |
| throws SAXException |
| { |
| // default behavior is to do nothing |
| } |
| |
| /** |
| * Return a {@link DOMSerializer} interface into this serializer. If the |
| * serializer does not support the {@link DOMSerializer} interface, it should |
| * return null. |
| * |
| * @return A {@link DOMSerializer} interface into this serializer, or null |
| * if the serializer is not DOM capable |
| * @throws IOException An I/O exception occured |
| * @see Serializer#asDOMSerializer() |
| */ |
| public DOMSerializer asDOMSerializer() throws IOException |
| { |
| return this; |
| } |
| |
| /** |
| * Tell if two strings are equal, without worry if the first string is null. |
| * |
| * @param p String reference, which may be null. |
| * @param t String reference, which may be null. |
| * |
| * @return true if strings are equal. |
| */ |
| private static final boolean subPartMatch(String p, String t) |
| { |
| return (p == t) || ((null != p) && (p.equals(t))); |
| } |
| |
| /** |
| * Returns the local name of a qualified name. |
| * If the name has no prefix, |
| * then it works as the identity (SAX2). |
| * |
| * @param qname a qualified name |
| * @return returns the prefix of the qualified name, |
| * or null if there is no prefix. |
| */ |
| protected static final String getPrefixPart(String qname) |
| { |
| final int col = qname.indexOf(':'); |
| return (col > 0) ? qname.substring(0, col) : null; |
| //return (col > 0) ? qname.substring(0,col) : ""; |
| } |
| |
| /** |
| * Some users of the serializer may need the current namespace mappings |
| * @return the current namespace mappings (prefix/uri) |
| * @see ExtendedContentHandler#getNamespaceMappings() |
| */ |
| public NamespaceMappings getNamespaceMappings() |
| { |
| return m_prefixMap; |
| } |
| |
| /** |
| * Returns the prefix currently pointing to the given URI (if any). |
| * @param namespaceURI the uri of the namespace in question |
| * @return a prefix pointing to the given URI (if any). |
| * @see ExtendedContentHandler#getPrefix(String) |
| */ |
| public String getPrefix(String namespaceURI) |
| { |
| String prefix = m_prefixMap.lookupPrefix(namespaceURI); |
| return prefix; |
| } |
| |
| /** |
| * Returns the URI of an element or attribute. Note that default namespaces |
| * do not apply directly to attributes. |
| * @param qname a qualified name |
| * @param isElement true if the qualified name is the name of |
| * an element. |
| * @return returns the namespace URI associated with the qualified name. |
| */ |
| public String getNamespaceURI(String qname, boolean isElement) |
| { |
| String uri = EMPTYSTRING; |
| int col = qname.lastIndexOf(':'); |
| final String prefix = (col > 0) ? qname.substring(0, col) : EMPTYSTRING; |
| |
| if (!EMPTYSTRING.equals(prefix) || isElement) |
| { |
| if (m_prefixMap != null) |
| { |
| uri = m_prefixMap.lookupNamespace(prefix); |
| if (uri == null && !prefix.equals(XMLNS_PREFIX)) |
| { |
| throw new RuntimeException( |
| Utils.messages.createMessage( |
| MsgKey.ER_NAMESPACE_PREFIX, |
| new Object[] { qname.substring(0, col) } )); |
| } |
| } |
| } |
| return uri; |
| } |
| |
| /** |
| * Returns the URI of prefix (if any) |
| * |
| * @param prefix the prefix whose URI is searched for |
| * @return the namespace URI currently associated with the |
| * prefix, null if the prefix is undefined. |
| */ |
| public String getNamespaceURIFromPrefix(String prefix) |
| { |
| String uri = null; |
| if (m_prefixMap != null) |
| uri = m_prefixMap.lookupNamespace(prefix); |
| return uri; |
| } |
| |
| /** |
| * Entity reference event. |
| * |
| * @param name Name of entity |
| * |
| * @throws org.xml.sax.SAXException |
| */ |
| public void entityReference(String name) throws org.xml.sax.SAXException |
| { |
| |
| flushPending(); |
| |
| startEntity(name); |
| endEntity(name); |
| |
| if (m_tracer != null) |
| fireEntityReference(name); |
| } |
| |
| /** |
| * Sets the transformer associated with this serializer |
| * @param t the transformer associated with this serializer. |
| * @see SerializationHandler#setTransformer(Transformer) |
| */ |
| public void setTransformer(Transformer t) |
| { |
| m_transformer = t; |
| |
| // If this transformer object implements the SerializerTrace interface |
| // then assign m_tracer to the transformer object so it can be used |
| // to fire trace events. |
| if ((m_transformer instanceof SerializerTrace) && |
| (((SerializerTrace) m_transformer).hasTraceListeners())) { |
| m_tracer = (SerializerTrace) m_transformer; |
| } else { |
| m_tracer = null; |
| } |
| } |
| /** |
| * Gets the transformer associated with this serializer |
| * @return returns the transformer associated with this serializer. |
| * @see SerializationHandler#getTransformer() |
| */ |
| public Transformer getTransformer() |
| { |
| return m_transformer; |
| } |
| |
| /** |
| * This method gets the nodes value as a String and uses that String as if |
| * it were an input character notification. |
| * @param node the Node to serialize |
| * @throws org.xml.sax.SAXException |
| */ |
| public void characters(org.w3c.dom.Node node) |
| throws org.xml.sax.SAXException |
| { |
| flushPending(); |
| String data = node.getNodeValue(); |
| if (data != null) |
| { |
| final int length = data.length(); |
| if (length > m_charsBuff.length) |
| { |
| m_charsBuff = new char[length * 2 + 1]; |
| } |
| data.getChars(0, length, m_charsBuff, 0); |
| characters(m_charsBuff, 0, length); |
| } |
| } |
| |
| |
| /** |
| * @see org.xml.sax.ErrorHandler#error(SAXParseException) |
| */ |
| public void error(SAXParseException exc) throws SAXException { |
| } |
| |
| /** |
| * @see org.xml.sax.ErrorHandler#fatalError(SAXParseException) |
| */ |
| public void fatalError(SAXParseException exc) throws SAXException { |
| |
| m_elemContext.m_startTagOpen = false; |
| |
| } |
| |
| /** |
| * @see org.xml.sax.ErrorHandler#warning(SAXParseException) |
| */ |
| public void warning(SAXParseException exc) throws SAXException |
| { |
| } |
| |
| /** |
| * To fire off start entity trace event |
| * @param name Name of entity |
| */ |
| protected void fireStartEntity(String name) |
| throws org.xml.sax.SAXException |
| { |
| if (m_tracer != null) |
| { |
| flushMyWriter(); |
| m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENTITYREF, name); |
| } |
| } |
| |
| /** |
| * Report the characters event |
| * @param chars content of characters |
| * @param start starting index of characters to output |
| * @param length number of characters to output |
| */ |
| // protected void fireCharEvent(char[] chars, int start, int length) |
| // throws org.xml.sax.SAXException |
| // { |
| // if (m_tracer != null) |
| // m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_CHARACTERS, chars, start,length); |
| // } |
| // |
| |
| /** |
| * This method is only used internally when flushing the writer from the |
| * various fire...() trace events. Due to the writer being wrapped with |
| * SerializerTraceWriter it may cause the flush of these trace events: |
| * EVENTTYPE_OUTPUT_PSEUDO_CHARACTERS |
| * EVENTTYPE_OUTPUT_CHARACTERS |
| * which trace the output written to the output stream. |
| * |
| */ |
| private void flushMyWriter() |
| { |
| if (m_writer != null) |
| { |
| try |
| { |
| m_writer.flush(); |
| } |
| catch(IOException ioe) |
| { |
| |
| } |
| } |
| } |
| /** |
| * Report the CDATA trace event |
| * @param chars content of CDATA |
| * @param start starting index of characters to output |
| * @param length number of characters to output |
| */ |
| protected void fireCDATAEvent(char[] chars, int start, int length) |
| throws org.xml.sax.SAXException |
| { |
| if (m_tracer != null) |
| { |
| flushMyWriter(); |
| m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_CDATA, chars, start,length); |
| } |
| } |
| |
| /** |
| * Report the comment trace event |
| * @param chars content of comment |
| * @param start starting index of comment to output |
| * @param length number of characters to output |
| */ |
| protected void fireCommentEvent(char[] chars, int start, int length) |
| throws org.xml.sax.SAXException |
| { |
| if (m_tracer != null) |
| { |
| flushMyWriter(); |
| m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_COMMENT, new String(chars, start, length)); |
| } |
| } |
| |
| |
| /** |
| * To fire off end entity trace event |
| * @param name Name of entity |
| */ |
| public void fireEndEntity(String name) |
| throws org.xml.sax.SAXException |
| { |
| if (m_tracer != null) |
| flushMyWriter(); |
| // we do not need to handle this. |
| } |
| |
| /** |
| * To fire off start document trace event |
| */ |
| protected void fireStartDoc() |
| throws org.xml.sax.SAXException |
| { |
| if (m_tracer != null) |
| { |
| flushMyWriter(); |
| m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_STARTDOCUMENT); |
| } |
| } |
| |
| |
| /** |
| * To fire off end document trace event |
| */ |
| protected void fireEndDoc() |
| throws org.xml.sax.SAXException |
| { |
| if (m_tracer != null) |
| { |
| flushMyWriter(); |
| m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENDDOCUMENT); |
| } |
| } |
| |
| /** |
| * Report the start element trace event. This trace method needs to be |
| * called just before the attributes are cleared. |
| * |
| * @param elemName the qualified name of the element |
| * |
| */ |
| protected void fireStartElem(String elemName) |
| throws org.xml.sax.SAXException |
| { |
| if (m_tracer != null) |
| { |
| flushMyWriter(); |
| m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_STARTELEMENT, |
| elemName, m_attributes); |
| } |
| } |
| |
| |
| /** |
| * To fire off the end element event |
| * @param name Name of element |
| */ |
| // protected void fireEndElem(String name) |
| // throws org.xml.sax.SAXException |
| // { |
| // if (m_tracer != null) |
| // m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENDELEMENT,name, (Attributes)null); |
| // } |
| |
| |
| /** |
| * To fire off the PI trace event |
| * @param name Name of PI |
| */ |
| protected void fireEscapingEvent(String name, String data) |
| throws org.xml.sax.SAXException |
| { |
| |
| if (m_tracer != null) |
| { |
| flushMyWriter(); |
| m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_PI,name, data); |
| } |
| } |
| |
| |
| /** |
| * To fire off the entity reference trace event |
| * @param name Name of entity reference |
| */ |
| protected void fireEntityReference(String name) |
| throws org.xml.sax.SAXException |
| { |
| if (m_tracer != null) |
| { |
| flushMyWriter(); |
| m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENTITYREF,name, (Attributes)null); |
| } |
| } |
| |
| /** |
| * Receive notification of the beginning of a document. |
| * This method is never a self generated call, |
| * but only called externally. |
| * |
| * <p>The SAX parser will invoke this method only once, before any |
| * other methods in this interface or in DTDHandler (except for |
| * setDocumentLocator).</p> |
| * |
| * @throws org.xml.sax.SAXException Any SAX exception, possibly |
| * wrapping another exception. |
| * |
| * @throws org.xml.sax.SAXException |
| */ |
| public void startDocument() throws org.xml.sax.SAXException |
| { |
| |
| // if we do get called with startDocument(), handle it right away |
| startDocumentInternal(); |
| m_needToCallStartDocument = false; |
| return; |
| } |
| |
| /** |
| * This method handles what needs to be done at a startDocument() call, |
| * whether from an external caller, or internally called in the |
| * serializer. For historical reasons the serializer is flexible to |
| * startDocument() not always being called. |
| * Even if no external call is |
| * made into startDocument() this method will always be called as a self |
| * generated internal startDocument, it handles what needs to be done at a |
| * startDocument() call. |
| * |
| * This method exists just to make sure that startDocument() is only ever |
| * called from an external caller, which in principle is just a matter of |
| * style. |
| * |
| * @throws SAXException |
| */ |
| protected void startDocumentInternal() throws org.xml.sax.SAXException |
| { |
| if (m_tracer != null) |
| this.fireStartDoc(); |
| } |
| /** |
| * This method is used to set the source locator, which might be used to |
| * generated an error message. |
| * @param locator the source locator |
| * |
| * @see ExtendedContentHandler#setSourceLocator(javax.xml.transform.SourceLocator) |
| */ |
| public void setSourceLocator(SourceLocator locator) |
| { |
| m_sourceLocator = locator; |
| } |
| |
| |
| /** |
| * Used only by TransformerSnapshotImpl to restore the serialization |
| * to a previous state. |
| * |
| * @param mappings NamespaceMappings |
| */ |
| public void setNamespaceMappings(NamespaceMappings mappings) { |
| m_prefixMap = mappings; |
| } |
| |
| public boolean reset() |
| { |
| resetSerializerBase(); |
| return true; |
| } |
| |
| /** |
| * Reset all of the fields owned by SerializerBase |
| * |
| */ |
| private void resetSerializerBase() |
| { |
| this.m_attributes.clear(); |
| this.m_CdataElems = null; |
| this.m_cdataTagOpen = false; |
| this.m_docIsEmpty = true; |
| this.m_doctypePublic = null; |
| this.m_doctypeSystem = null; |
| this.m_doIndent = false; |
| this.m_elemContext = new ElemContext(); |
| this.m_indentAmount = 0; |
| this.m_inEntityRef = false; |
| this.m_inExternalDTD = false; |
| this.m_mediatype = null; |
| this.m_needToCallStartDocument = true; |
| this.m_needToOutputDocTypeDecl = false; |
| if (m_OutputProps != null) |
| this.m_OutputProps.clear(); |
| if (m_OutputPropsDefault != null) |
| this.m_OutputPropsDefault.clear(); |
| if (this.m_prefixMap != null) |
| this.m_prefixMap.reset(); |
| this.m_shouldNotWriteXMLHeader = false; |
| this.m_sourceLocator = null; |
| this.m_standalone = null; |
| this.m_standaloneWasSpecified = false; |
| this.m_StringOfCDATASections = null; |
| this.m_tracer = null; |
| this.m_transformer = null; |
| this.m_version = null; |
| // don't set writer to null, so that it might be re-used |
| //this.m_writer = null; |
| } |
| |
| /** |
| * Returns true if the serializer is used for temporary output rather than |
| * final output. |
| * |
| * This concept is made clear in the XSLT 2.0 draft. |
| */ |
| final boolean inTemporaryOutputState() |
| { |
| /* This is a hack. We should really be letting the serializer know |
| * that it is in temporary output state with an explicit call, but |
| * from a pragmatic point of view (for now anyways) having no output |
| * encoding at all, not even the default UTF-8 indicates that the serializer |
| * is being used for temporary RTF. |
| */ |
| return (getEncoding() == null); |
| |
| } |
| |
| /** |
| * This method adds an attribute the the current element, |
| * but should not be used for an xsl:attribute child. |
| * @see ExtendedContentHandler#addAttribute(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) |
| */ |
| public void addAttribute(String uri, String localName, String rawName, String type, String value) throws SAXException |
| { |
| if (m_elemContext.m_startTagOpen) |
| { |
| addAttributeAlways(uri, localName, rawName, type, value, false); |
| } |
| } |
| |
| /** |
| * @see org.xml.sax.DTDHandler#notationDecl(java.lang.String, java.lang.String, java.lang.String) |
| */ |
| public void notationDecl(String arg0, String arg1, String arg2) |
| throws SAXException { |
| // This method just provides a definition to satisfy the interface |
| // A particular sub-class of SerializerBase provides the implementation (if desired) |
| } |
| |
| /** |
| * @see org.xml.sax.DTDHandler#unparsedEntityDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String) |
| */ |
| public void unparsedEntityDecl( |
| String arg0, |
| String arg1, |
| String arg2, |
| String arg3) |
| throws SAXException { |
| // This method just provides a definition to satisfy the interface |
| // A particular sub-class of SerializerBase provides the implementation (if desired) |
| } |
| |
| /** |
| * If set to false the serializer does not expand DTD entities, |
| * but leaves them as is, the default value is true. |
| */ |
| public void setDTDEntityExpansion(boolean expand) { |
| // This method just provides a definition to satisfy the interface |
| // A particular sub-class of SerializerBase provides the implementation (if desired) |
| } |
| |
| |
| /** |
| * The CDATA section names stored in a whitespace separateed list with |
| * each element being a word of the form "{uri}localName" This list |
| * comes from the cdata-section-elements attribute. |
| * |
| * This field replaces m_cdataSectionElements Vector. |
| */ |
| protected String m_StringOfCDATASections = null; |
| |
| boolean m_docIsEmpty = true; |
| void initCdataElems(String s) |
| { |
| if (s != null) |
| { |
| int max = s.length(); |
| |
| // true if we are in the middle of a pair of curly braces that delimit a URI |
| boolean inCurly = false; |
| |
| // true if we found a URI but haven't yet processed the local name |
| boolean foundURI = false; |
| |
| StringBuffer buf = new StringBuffer(); |
| String uri = null; |
| String localName = null; |
| |
| // parse through string, breaking on whitespaces. I do this instead |
| // of a tokenizer so I can track whitespace inside of curly brackets, |
| // which theoretically shouldn't happen if they contain legal URLs. |
| |
| |
| for (int i = 0; i < max; i++) |
| { |
| |
| char c = s.charAt(i); |
| |
| if (Character.isWhitespace(c)) |
| { |
| if (!inCurly) |
| { |
| if (buf.length() > 0) |
| { |
| localName = buf.toString(); |
| if (!foundURI) |
| uri = ""; |
| addCDATAElement(uri,localName); |
| buf.setLength(0); |
| foundURI = false; |
| } |
| continue; |
| } |
| else |
| buf.append(c); // add whitespace to the URI |
| } |
| else if ('{' == c) // starting a URI |
| inCurly = true; |
| else if ('}' == c) |
| { |
| // we just ended a URI, add the URI to the vector |
| foundURI = true; |
| uri = buf.toString(); |
| buf.setLength(0); |
| inCurly = false; |
| } |
| else |
| { |
| // append non-whitespace, non-curly to current URI or localName being gathered. |
| buf.append(c); |
| } |
| |
| } |
| |
| if (buf.length() > 0) |
| { |
| // We have one last localName to process. |
| localName = buf.toString(); |
| if (!foundURI) |
| uri = ""; |
| addCDATAElement(uri,localName); |
| } |
| } |
| } |
| protected java.util.Hashtable m_CdataElems = null; |
| private void addCDATAElement(String uri, String localName) |
| { |
| if (m_CdataElems == null) { |
| m_CdataElems = new java.util.Hashtable(); |
| } |
| |
| java.util.Hashtable h = (java.util.Hashtable) m_CdataElems.get(localName); |
| if (h == null) { |
| h = new java.util.Hashtable(); |
| m_CdataElems.put(localName,h); |
| } |
| h.put(uri,uri); |
| |
| } |
| |
| |
| /** |
| * Return true if nothing has been sent to this result tree yet. |
| * <p> |
| * This is not a public API. |
| * |
| * @xsl.usage internal |
| */ |
| public boolean documentIsEmpty() { |
| // If we haven't called startDocument() yet, then this document is empty |
| return m_docIsEmpty && (m_elemContext.m_currentElemDepth == 0); |
| } |
| |
| /** |
| * Return true if the current element in m_elemContext |
| * is a CDATA section. |
| * CDATA sections are specified in the <xsl:output> attribute |
| * cdata-section-names or in the JAXP equivalent property. |
| * In any case the format of the value of such a property is: |
| * <pre> |
| * "{uri1}localName1 {uri2}localName2 . . . " |
| * </pre> |
| * |
| * <p> |
| * This method is not a public API, but is only used internally by the serializer. |
| */ |
| protected boolean isCdataSection() |
| { |
| |
| boolean b = false; |
| |
| if (null != m_StringOfCDATASections) |
| { |
| if (m_elemContext.m_elementLocalName == null) |
| { |
| String localName = getLocalName(m_elemContext.m_elementName); |
| m_elemContext.m_elementLocalName = localName; |
| } |
| |
| if ( m_elemContext.m_elementURI == null) { |
| |
| m_elemContext.m_elementURI = getElementURI(); |
| } |
| else if ( m_elemContext.m_elementURI.length() == 0) { |
| if ( m_elemContext.m_elementName == null) { |
| m_elemContext.m_elementName = m_elemContext.m_elementLocalName; |
| // leave URI as "", meaning in no namespace |
| } |
| else if (m_elemContext.m_elementLocalName.length() < m_elemContext.m_elementName.length()){ |
| // We were told the URI was "", yet the name has a prefix since the name is longer than the localname. |
| // So we will fix that incorrect information here. |
| m_elemContext.m_elementURI = getElementURI(); |
| } |
| } |
| |
| java.util.Hashtable h = (java.util.Hashtable) m_CdataElems.get(m_elemContext.m_elementLocalName); |
| if (h != null) |
| { |
| Object obj = h.get(m_elemContext.m_elementURI); |
| if (obj != null) |
| b = true; |
| } |
| |
| } |
| return b; |
| } |
| |
| /** |
| * Before this call m_elementContext.m_elementURI is null, |
| * which means it is not yet known. After this call it |
| * is non-null, but possibly "" meaning that it is in the |
| * default namespace. |
| * |
| * @return The URI of the element, never null, but possibly "". |
| */ |
| private String getElementURI() { |
| String uri = null; |
| // At this point in processing we have received all the |
| // namespace mappings |
| // As we still don't know the elements namespace, |
| // we now figure it out. |
| |
| String prefix = getPrefixPart(m_elemContext.m_elementName); |
| |
| if (prefix == null) { |
| // no prefix so lookup the URI of the default namespace |
| uri = m_prefixMap.lookupNamespace(""); |
| } else { |
| uri = m_prefixMap.lookupNamespace(prefix); |
| } |
| if (uri == null) { |
| // We didn't find the namespace for the |
| // prefix ... ouch, that shouldn't happen. |
| // This is a hack, we really don't know |
| // the namespace |
| uri = EMPTYSTRING; |
| } |
| |
| return uri; |
| } |
| |
| |
| /** |
| * Get the value of an output property, |
| * the explicit value, if any, otherwise the |
| * default value, if any, otherwise null. |
| */ |
| public String getOutputProperty(String name) { |
| String val = getOutputPropertyNonDefault(name); |
| // If no explicit value, try to get the default value |
| if (val == null) |
| val = getOutputPropertyDefault(name); |
| return val; |
| |
| } |
| /** |
| * Get the value of an output property, |
| * not the default value. If there is a default |
| * value, but no non-default value this method |
| * will return null. |
| * <p> |
| * |
| */ |
| public String getOutputPropertyNonDefault(String name ) |
| { |
| return getProp(name,false); |
| } |
| |
| /** |
| * Return a {@link DOM3Serializer} interface into this serializer. If the |
| * serializer does not support the {@link DOM3Serializer} interface, it should |
| * return null. |
| * |
| * @return A {@link DOM3Serializer} interface into this serializer, or null |
| * if the serializer is not DOM capable |
| * @throws IOException An I/O exception occured |
| * @see org.apache.xml.serializer.Serializer#asDOM3Serializer() |
| */ |
| public Object asDOM3Serializer() throws IOException |
| { |
| return new org.apache.xml.serializer.dom3.DOM3SerializerImpl(this); |
| } |
| /** |
| * Get the default value of an xsl:output property, |
| * which would be null only if no default value exists |
| * for the property. |
| */ |
| public String getOutputPropertyDefault(String name) { |
| return getProp(name, true); |
| } |
| |
| /** |
| * Set the value for the output property, typically from |
| * an xsl:output element, but this does not change what |
| * the default value is. |
| */ |
| public void setOutputProperty(String name, String val) { |
| setProp(name,val,false); |
| |
| } |
| |
| /** |
| * Set the default value for an output property, but this does |
| * not impact any explicitly set value. |
| */ |
| public void setOutputPropertyDefault(String name, String val) { |
| setProp(name,val,true); |
| |
| } |
| |
| /** |
| * A mapping of keys to explicitly set values, for example if |
| * and <xsl:output/> has an "encoding" attribute, this |
| * map will have what that attribute maps to. |
| */ |
| private HashMap m_OutputProps; |
| /** |
| * A mapping of keys to default values, for example if |
| * the default value of the encoding is "UTF-8" then this |
| * map will have that "encoding" maps to "UTF-8". |
| */ |
| private HashMap m_OutputPropsDefault; |
| |
| Set getOutputPropDefaultKeys() { |
| return m_OutputPropsDefault.keySet(); |
| } |
| Set getOutputPropKeys() { |
| return m_OutputProps.keySet(); |
| } |
| |
| private String getProp(String name, boolean defaultVal) { |
| if (m_OutputProps == null) { |
| m_OutputProps = new HashMap(); |
| m_OutputPropsDefault = new HashMap(); |
| } |
| |
| String val; |
| if (defaultVal) |
| val = (String) m_OutputPropsDefault.get(name); |
| else |
| val = (String) m_OutputProps.get(name); |
| |
| return val; |
| |
| } |
| /** |
| * |
| * @param name The name of the property, e.g. "{http://myprop}indent-tabs" or "indent". |
| * @param val The value of the property, e.g. "4" |
| * @param defaultVal true if this is a default value being set for the property as |
| * opposed to a user define on, set say explicitly in the stylesheet or via JAXP |
| */ |
| void setProp(String name, String val, boolean defaultVal) { |
| if (m_OutputProps == null) { |
| m_OutputProps = new HashMap(); |
| m_OutputPropsDefault = new HashMap(); |
| } |
| |
| if (defaultVal) |
| m_OutputPropsDefault.put(name,val); |
| else { |
| if (OutputKeys.CDATA_SECTION_ELEMENTS.equals(name) && val != null) { |
| initCdataElems(val); |
| String oldVal = (String) m_OutputProps.get(name); |
| String newVal; |
| if (oldVal == null) |
| newVal = oldVal + ' ' + val; |
| else |
| newVal = val; |
| m_OutputProps.put(name,newVal); |
| } |
| else { |
| m_OutputProps.put(name,val); |
| } |
| } |
| |
| |
| } |
| |
| /** |
| * Get the first char of the local name |
| * @param name Either a local name, or a local name |
| * preceeded by a uri enclosed in curly braces. |
| */ |
| static char getFirstCharLocName(String name) { |
| final char first; |
| int i = name.indexOf('}'); |
| if (i < 0) |
| first = name.charAt(0); |
| else |
| first = name.charAt(i+1); |
| return first; |
| } |
| } |
| |
| |