1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the  "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18/*
19 * $Id: SerializerUtils.java 468642 2006-10-28 06:55:10Z minchau $
20 */
21package org.apache.xalan.serialize;
22
23import javax.xml.transform.TransformerException;
24
25import org.apache.xalan.transformer.TransformerImpl;
26import org.apache.xml.dtm.DTM;
27import org.apache.xml.serializer.NamespaceMappings;
28import org.apache.xml.serializer.SerializationHandler;
29import org.apache.xpath.XPathContext;
30import org.apache.xpath.objects.XObject;
31import org.xml.sax.SAXException;
32
33/**
34 * Class that contains only static methods that are used to "serialize",
35 * these methods are used by Xalan and are not in org.apache.xml.serializer
36 * because they have dependancies on the packages org.apache.xpath or org.
37 * apache.xml.dtm or org.apache.xalan.transformer. The package org.apache.xml.
38 * serializer should not depend on Xalan or XSLTC.
39 * @xsl.usage internal
40 */
41public class SerializerUtils
42{
43
44    /**
45     * Copy an DOM attribute to the created output element, executing
46     * attribute templates as need be, and processing the xsl:use
47     * attribute.
48     *
49     * @param handler SerializationHandler to which the attributes are added.
50     * @param attr Attribute node to add to SerializationHandler.
51     *
52     * @throws TransformerException
53     */
54    public static void addAttribute(SerializationHandler handler, int attr)
55        throws TransformerException
56    {
57
58        TransformerImpl transformer =
59            (TransformerImpl) handler.getTransformer();
60        DTM dtm = transformer.getXPathContext().getDTM(attr);
61
62        if (SerializerUtils.isDefinedNSDecl(handler, attr, dtm))
63            return;
64
65        String ns = dtm.getNamespaceURI(attr);
66
67        if (ns == null)
68            ns = "";
69
70        // %OPT% ...can I just store the node handle?
71        try
72        {
73            handler.addAttribute(
74                ns,
75                dtm.getLocalName(attr),
76                dtm.getNodeName(attr),
77                "CDATA",
78                dtm.getNodeValue(attr), false);
79        }
80        catch (SAXException e)
81        {
82            // do something?
83        }
84    } // end copyAttributeToTarget method
85
86    /**
87     * Copy DOM attributes to the result element.
88     *
89     * @param src Source node with the attributes
90     *
91     * @throws TransformerException
92     */
93    public static void addAttributes(SerializationHandler handler, int src)
94        throws TransformerException
95    {
96
97        TransformerImpl transformer =
98            (TransformerImpl) handler.getTransformer();
99        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}
274