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 }