001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: SerializerUtils.java 468642 2006-10-28 06:55:10Z minchau $
020     */
021    package org.apache.xalan.serialize;
022    
023    import javax.xml.transform.TransformerException;
024    
025    import org.apache.xalan.transformer.TransformerImpl;
026    import org.apache.xml.dtm.DTM;
027    import org.apache.xml.serializer.NamespaceMappings;
028    import org.apache.xml.serializer.SerializationHandler;
029    import org.apache.xpath.XPathContext;
030    import org.apache.xpath.objects.XObject;
031    import org.xml.sax.SAXException;
032    
033    /**
034     * Class that contains only static methods that are used to "serialize",
035     * these methods are used by Xalan and are not in org.apache.xml.serializer
036     * because they have dependancies on the packages org.apache.xpath or org.
037     * apache.xml.dtm or org.apache.xalan.transformer. The package org.apache.xml.
038     * serializer should not depend on Xalan or XSLTC.
039     * @xsl.usage internal
040     */
041    public class SerializerUtils
042    {
043    
044        /**
045         * Copy an DOM attribute to the created output element, executing
046         * attribute templates as need be, and processing the xsl:use
047         * attribute.
048         *
049         * @param handler SerializationHandler to which the attributes are added.
050         * @param attr Attribute node to add to SerializationHandler.
051         *
052         * @throws TransformerException
053         */
054        public static void addAttribute(SerializationHandler handler, int attr)
055            throws TransformerException
056        {
057    
058            TransformerImpl transformer =
059                (TransformerImpl) handler.getTransformer();
060            DTM dtm = transformer.getXPathContext().getDTM(attr);
061    
062            if (SerializerUtils.isDefinedNSDecl(handler, attr, dtm))
063                return;
064    
065            String ns = dtm.getNamespaceURI(attr);
066    
067            if (ns == null)
068                ns = "";
069    
070            // %OPT% ...can I just store the node handle?
071            try
072            {
073                handler.addAttribute(
074                    ns,
075                    dtm.getLocalName(attr),
076                    dtm.getNodeName(attr),
077                    "CDATA",
078                    dtm.getNodeValue(attr), false);
079            }
080            catch (SAXException e)
081            {
082                // do something?
083            }
084        } // end copyAttributeToTarget method
085    
086        /**
087         * Copy DOM attributes to the result element.
088         *
089         * @param src Source node with the attributes
090         *
091         * @throws TransformerException
092         */
093        public static void addAttributes(SerializationHandler handler, int src)
094            throws TransformerException
095        {
096    
097            TransformerImpl transformer =
098                (TransformerImpl) handler.getTransformer();
099            DTM dtm = transformer.getXPathContext().getDTM(src);
100    
101            for (int node = dtm.getFirstAttribute(src);
102                DTM.NULL != node;
103                node = dtm.getNextAttribute(node))
104            {
105                addAttribute(handler, node);
106            }
107        }
108    
109        /**
110         * Given a result tree fragment, walk the tree and
111         * output it to the SerializationHandler.
112         *
113         * @param obj Result tree fragment object
114         * @param support XPath context for the result tree fragment
115         *
116         * @throws org.xml.sax.SAXException
117         */
118        public static void outputResultTreeFragment(
119            SerializationHandler handler,
120            XObject obj,
121            XPathContext support)
122            throws org.xml.sax.SAXException
123        {
124    
125            int doc = obj.rtf();
126            DTM dtm = support.getDTM(doc);
127    
128            if (null != dtm)
129            {
130                for (int n = dtm.getFirstChild(doc);
131                    DTM.NULL != n;
132                    n = dtm.getNextSibling(n))
133                {
134                    handler.flushPending();
135    
136                    // I think. . . . This used to have a (true) arg
137                    // to flush prefixes, will that cause problems ???
138                    if (dtm.getNodeType(n) == DTM.ELEMENT_NODE
139                            && dtm.getNamespaceURI(n) == null)
140                        handler.startPrefixMapping("", "");
141                    dtm.dispatchToEvents(n, handler);
142                }
143            }
144        }
145    
146        /**
147         * Copy <KBD>xmlns:</KBD> attributes in if not already in scope.
148         *
149         * As a quick hack to support ClonerToResultTree, this can also be used
150         * to copy an individual namespace node.
151         *
152         * @param src Source Node
153         * NEEDSDOC @param type
154         * NEEDSDOC @param dtm
155         *
156         * @throws TransformerException
157         */
158        public static void processNSDecls(
159            SerializationHandler handler,
160            int src,
161            int type,
162            DTM dtm)
163            throws TransformerException
164        {
165    
166            try
167            {
168                if (type == DTM.ELEMENT_NODE)
169                {
170                    for (int namespace = dtm.getFirstNamespaceNode(src, true);
171                        DTM.NULL != namespace;
172                        namespace = dtm.getNextNamespaceNode(src, namespace, true))
173                    {
174    
175                        // String prefix = dtm.getPrefix(namespace);
176                        String prefix = dtm.getNodeNameX(namespace);
177                        String desturi = handler.getNamespaceURIFromPrefix(prefix);
178                        //            String desturi = getURI(prefix);
179                        String srcURI = dtm.getNodeValue(namespace);
180    
181                        if (!srcURI.equalsIgnoreCase(desturi))
182                        {
183                            handler.startPrefixMapping(prefix, srcURI, false);
184                        }
185                    }
186                }
187                else if (type == DTM.NAMESPACE_NODE)
188                {
189                    String prefix = dtm.getNodeNameX(src);
190                    // Brian M. - some changes here to get desturi
191                    String desturi = handler.getNamespaceURIFromPrefix(prefix);
192                    String srcURI = dtm.getNodeValue(src);
193    
194                    if (!srcURI.equalsIgnoreCase(desturi))
195                    {
196                        handler.startPrefixMapping(prefix, srcURI, false);
197                    }
198                }
199            }
200            catch (org.xml.sax.SAXException se)
201            {
202                throw new TransformerException(se);
203            }
204        }
205    
206        /**
207         * Returns whether a namespace is defined
208         *
209         *
210         * @param attr Namespace attribute node
211         * @param dtm The DTM that owns attr.
212         *
213         * @return True if the namespace is already defined in
214         * list of namespaces
215         */
216        public static boolean isDefinedNSDecl(
217            SerializationHandler serializer,
218            int attr,
219            DTM dtm)
220        {
221    
222            if (DTM.NAMESPACE_NODE == dtm.getNodeType(attr))
223            {
224    
225                // String prefix = dtm.getPrefix(attr);
226                String prefix = dtm.getNodeNameX(attr);
227                String uri = serializer.getNamespaceURIFromPrefix(prefix);
228                //      String uri = getURI(prefix);
229    
230                if ((null != uri) && uri.equals(dtm.getStringValue(attr)))
231                    return true;
232            }
233    
234            return false;
235        }
236    
237        /**
238         * This function checks to make sure a given prefix is really
239         * declared.  It might not be, because it may be an excluded prefix.
240         * If it's not, it still needs to be declared at this point.
241         * TODO: This needs to be done at an earlier stage in the game... -sb
242         *
243         * NEEDSDOC @param dtm
244         * NEEDSDOC @param namespace
245         *
246         * @throws org.xml.sax.SAXException
247         */
248        public static void ensureNamespaceDeclDeclared(
249            SerializationHandler handler,
250            DTM dtm,
251            int namespace)
252            throws org.xml.sax.SAXException
253        {
254    
255            String uri = dtm.getNodeValue(namespace);
256            String prefix = dtm.getNodeNameX(namespace);
257    
258            if ((uri != null && uri.length() > 0) && (null != prefix))
259            {
260                String foundURI;
261                NamespaceMappings ns = handler.getNamespaceMappings();
262                if (ns != null)
263                {
264    
265                    foundURI = ns.lookupNamespace(prefix);
266                    if ((null == foundURI) || !foundURI.equals(uri))
267                    {
268                        handler.startPrefixMapping(prefix, uri, false);
269                    }
270                }
271            }
272        }
273    }