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 }