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  */
21 package org.apache.xalan.serialize;
22 
23 import javax.xml.transform.TransformerException;
24 
25 import org.apache.xalan.transformer.TransformerImpl;
26 import org.apache.xml.dtm.DTM;
27 import org.apache.xml.serializer.NamespaceMappings;
28 import org.apache.xml.serializer.SerializationHandler;
29 import org.apache.xpath.XPathContext;
30 import org.apache.xpath.objects.XObject;
31 import 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  */
41 public 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      */
addAttribute(SerializationHandler handler, int attr)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      */
addAttributes(SerializationHandler handler, int src)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      */
outputResultTreeFragment( SerializationHandler handler, XObject obj, XPathContext support)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      */
processNSDecls( SerializationHandler handler, int src, int type, DTM dtm)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      */
isDefinedNSDecl( SerializationHandler serializer, int attr, DTM dtm)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      */
ensureNamespaceDeclDeclared( SerializationHandler handler, DTM dtm, int namespace)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