XMLStreamReaderUtil.java revision 524:dcaa586ab756
12311Sjkh/* 22311Sjkh * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 32311Sjkh * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 42311Sjkh * 52311Sjkh * This code is free software; you can redistribute it and/or modify it 62311Sjkh * under the terms of the GNU General Public License version 2 only, as 72311Sjkh * published by the Free Software Foundation. Oracle designates this 82311Sjkh * particular file as subject to the "Classpath" exception as provided 92311Sjkh * by Oracle in the LICENSE file that accompanied this code. 102311Sjkh * 112311Sjkh * This code is distributed in the hope that it will be useful, but WITHOUT 122311Sjkh * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 132311Sjkh * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 142311Sjkh * version 2 for more details (a copy is included in the LICENSE file that 152311Sjkh * accompanied this code). 162311Sjkh * 172311Sjkh * You should have received a copy of the GNU General Public License version 182311Sjkh * 2 along with this work; if not, write to the Free Software Foundation, 1950479Speter * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 202311Sjkh * 212311Sjkh * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 222311Sjkh * or visit www.oracle.com if you need additional information or have any 232311Sjkh * questions. 242311Sjkh */ 252311Sjkh 262311Sjkhpackage com.sun.xml.internal.ws.streaming; 272311Sjkh 282311Sjkhimport javax.xml.namespace.QName; 292311Sjkhimport static javax.xml.stream.XMLStreamConstants.*; 302311Sjkhimport javax.xml.stream.XMLStreamException; 312311Sjkhimport javax.xml.stream.XMLStreamReader; 322311Sjkhimport javax.xml.stream.XMLStreamConstants; 332311Sjkh 342311Sjkh/** 352311Sjkh * <p> XMLStreamReaderUtil provides some utility methods intended to be used 362311Sjkh * in conjunction with a StAX XMLStreamReader. </p> 372311Sjkh * 382311Sjkh * @author WS Development Team 392311Sjkh */ 402311Sjkhpublic class XMLStreamReaderUtil { 412311Sjkh 422311Sjkh private XMLStreamReaderUtil() { 432311Sjkh } 442311Sjkh 452311Sjkh public static void close(XMLStreamReader reader) { 462311Sjkh try { 472311Sjkh reader.close(); 482311Sjkh } catch (XMLStreamException e) { 492311Sjkh throw wrapException(e); 502311Sjkh } 512311Sjkh } 522311Sjkh 532311Sjkh public static void readRest(XMLStreamReader reader) { 542311Sjkh try { 552311Sjkh while(reader.getEventType() != XMLStreamConstants.END_DOCUMENT) { 562311Sjkh reader.next(); 572311Sjkh } 582311Sjkh } catch (XMLStreamException e) { 592311Sjkh throw wrapException(e); 602311Sjkh } 612311Sjkh } 622311Sjkh 632311Sjkh public static int next(XMLStreamReader reader) { 642311Sjkh try { 652311Sjkh int readerEvent = reader.next(); 662311Sjkh 672311Sjkh while (readerEvent != END_DOCUMENT) { 682311Sjkh switch (readerEvent) { 692311Sjkh case START_ELEMENT: 702311Sjkh case END_ELEMENT: 712311Sjkh case CDATA: 722311Sjkh case CHARACTERS: 732311Sjkh case PROCESSING_INSTRUCTION: 742311Sjkh return readerEvent; 752311Sjkh default: 762311Sjkh // falls through ignoring event 772311Sjkh } 782311Sjkh readerEvent = reader.next(); 792311Sjkh } 802311Sjkh 812311Sjkh return readerEvent; 822311Sjkh } 832311Sjkh catch (XMLStreamException e) { 842311Sjkh throw wrapException(e); 852311Sjkh } 862311Sjkh } 872311Sjkh 882311Sjkh public static int nextElementContent(XMLStreamReader reader) { 892311Sjkh int state = nextContent(reader); 902311Sjkh if (state == CHARACTERS) { 912311Sjkh throw new XMLStreamReaderException( 922311Sjkh "xmlreader.unexpectedCharacterContent", reader.getText()); 932311Sjkh } 942311Sjkh return state; 952311Sjkh } 962311Sjkh 972311Sjkh public static void toNextTag(XMLStreamReader reader, QName name) { 982311Sjkh // skip any whitespace 992311Sjkh if (reader.getEventType() != XMLStreamConstants.START_ELEMENT && 1002311Sjkh reader.getEventType() != XMLStreamConstants.END_ELEMENT) { 1012311Sjkh XMLStreamReaderUtil.nextElementContent(reader); 1022311Sjkh } 1032311Sjkh if(reader.getEventType() == XMLStreamConstants.END_ELEMENT && name.equals(reader.getName())) { 1042311Sjkh XMLStreamReaderUtil.nextElementContent(reader); 1052311Sjkh } 1062311Sjkh } 1072311Sjkh 1082311Sjkh /** 1098169Sache * Moves next and read spaces from the reader as long as to the next element. 1108169Sache * Comments are ignored 1118169Sache * @param reader 1122311Sjkh * @return 1132311Sjkh */ 1148169Sache public static String nextWhiteSpaceContent(XMLStreamReader reader) { 1152311Sjkh next(reader); 1162311Sjkh return currentWhiteSpaceContent(reader); 1172311Sjkh } 1182311Sjkh 1192311Sjkh /** 1202311Sjkh * Read spaces from the reader as long as to the next element, starting from 1212311Sjkh * current position. Comments are ignored. 1222311Sjkh * @param reader 1232311Sjkh * @return 1242311Sjkh */ 1252311Sjkh public static String currentWhiteSpaceContent(XMLStreamReader reader) { 1262311Sjkh 1272311Sjkh // since the there might be several valid chunks (spaces/comment/spaces) 1282311Sjkh // StringBuilder must be used; it's initialized lazily, only when needed 1292311Sjkh StringBuilder whiteSpaces = null; 1302311Sjkh 1312311Sjkh for (;;) { 1322311Sjkh switch (reader.getEventType()) { 1332311Sjkh case START_ELEMENT: 1342311Sjkh case END_ELEMENT: 1352311Sjkh case END_DOCUMENT: 1362311Sjkh return whiteSpaces == null ? null : whiteSpaces.toString(); 1372311Sjkh case CHARACTERS: 1382311Sjkh if (reader.isWhiteSpace()) { 1392311Sjkh if (whiteSpaces == null) { 1402311Sjkh whiteSpaces = new StringBuilder(); 141 } 142 whiteSpaces.append(reader.getText()); 143 } else { 144 throw new XMLStreamReaderException( 145 "xmlreader.unexpectedCharacterContent", reader.getText()); 146 } 147 } 148 next(reader); 149 } 150 } 151 152 public static int nextContent(XMLStreamReader reader) { 153 for (;;) { 154 int state = next(reader); 155 switch (state) { 156 case START_ELEMENT: 157 case END_ELEMENT: 158 case END_DOCUMENT: 159 return state; 160 case CHARACTERS: 161 if (!reader.isWhiteSpace()) { 162 return CHARACTERS; 163 } 164 } 165 } 166 } 167 168 /** 169 * Skip current element, leaving the cursor at END_ELEMENT of 170 * current element. 171 */ 172 public static void skipElement(XMLStreamReader reader) { 173 assert reader.getEventType() == START_ELEMENT; 174 skipTags(reader, true); 175 assert reader.getEventType() == END_ELEMENT; 176 } 177 178 /** 179 * Skip following siblings, leaving cursor at END_ELEMENT of 180 * parent element. 181 */ 182 public static void skipSiblings(XMLStreamReader reader, QName parent) { 183 skipTags(reader, reader.getName().equals(parent)); 184 assert reader.getEventType() == END_ELEMENT; 185 } 186 187 private static void skipTags(XMLStreamReader reader, boolean exitCondition) { 188 try { 189 int state, tags = 0; 190 while ((state = reader.next()) != END_DOCUMENT) { 191 if (state == START_ELEMENT) { 192 tags++; 193 } 194 else if (state == END_ELEMENT) { 195 if (tags == 0 && exitCondition) return; 196 tags--; 197 } 198 } 199 } 200 catch (XMLStreamException e) { 201 throw wrapException(e); 202 } 203 } 204 205 /* 206 * Get the text of an element 207 */ 208 public static String getElementText(XMLStreamReader reader) { 209 try { 210 return reader.getElementText(); 211 } catch (XMLStreamException e) { 212 throw wrapException(e); 213 } 214 } 215 216 /* 217 * Get a QName with 'someUri' and 'localname' from an 218 * element of qname type: 219 * <xyz xmlns:ns1="someUri">ns1:localname</xyz> 220 */ 221 public static QName getElementQName(XMLStreamReader reader) { 222 try { 223 String text = reader.getElementText().trim(); 224 String prefix = text.substring(0,text.indexOf(':')); 225 String namespaceURI = reader.getNamespaceContext().getNamespaceURI(prefix); 226 if (namespaceURI == null) { 227 namespaceURI = ""; 228 } 229 String localPart = text.substring( 230 text.indexOf(':') + 1, text.length()); 231 return new QName(namespaceURI, localPart); 232 } catch (XMLStreamException e) { 233 throw wrapException(e); 234 } 235 } 236 237 /** 238 * Read all attributes into an data structure. Note that this method cannot 239 * be called multiple times to get the same list of attributes. 240 */ 241 public static Attributes getAttributes(XMLStreamReader reader) { 242 return (reader.getEventType() == START_ELEMENT || 243 reader.getEventType() == ATTRIBUTE) ? 244 new AttributesImpl(reader) : null; 245 } 246 247 public static void verifyReaderState(XMLStreamReader reader, int expectedState) { 248 int state = reader.getEventType(); 249 if (state != expectedState) { 250 throw new XMLStreamReaderException( 251 "xmlreader.unexpectedState", 252 getStateName(expectedState), getStateName(state)); 253 } 254 } 255 256 public static void verifyTag(XMLStreamReader reader, String namespaceURI, String localName) { 257 if (!localName.equals(reader.getLocalName()) || !namespaceURI.equals(reader.getNamespaceURI())) { 258 throw new XMLStreamReaderException( 259 "xmlreader.unexpectedState.tag", 260 "{" + namespaceURI + "}" + localName, 261 "{" + reader.getNamespaceURI() + "}" + reader.getLocalName()); 262 } 263 } 264 265 public static void verifyTag(XMLStreamReader reader, QName name) { 266 verifyTag(reader, name.getNamespaceURI(), name.getLocalPart()); 267 } 268 269 public static String getStateName(XMLStreamReader reader) { 270 return getStateName(reader.getEventType()); 271 } 272 273 public static String getStateName(int state) { 274 switch (state) { 275 case ATTRIBUTE: 276 return "ATTRIBUTE"; 277 case CDATA: 278 return "CDATA"; 279 case CHARACTERS: 280 return "CHARACTERS"; 281 case COMMENT: 282 return "COMMENT"; 283 case DTD: 284 return "DTD"; 285 case END_DOCUMENT: 286 return "END_DOCUMENT"; 287 case END_ELEMENT: 288 return "END_ELEMENT"; 289 case ENTITY_DECLARATION: 290 return "ENTITY_DECLARATION"; 291 case ENTITY_REFERENCE: 292 return "ENTITY_REFERENCE"; 293 case NAMESPACE: 294 return "NAMESPACE"; 295 case NOTATION_DECLARATION: 296 return "NOTATION_DECLARATION"; 297 case PROCESSING_INSTRUCTION: 298 return "PROCESSING_INSTRUCTION"; 299 case SPACE: 300 return "SPACE"; 301 case START_DOCUMENT: 302 return "START_DOCUMENT"; 303 case START_ELEMENT: 304 return "START_ELEMENT"; 305 default : 306 return "UNKNOWN"; 307 } 308 } 309 310 private static XMLStreamReaderException wrapException(XMLStreamException e) { 311 return new XMLStreamReaderException("xmlreader.ioException",e); 312 } 313 314 // -- Auxiliary classes ---------------------------------------------- 315 316 /** 317 * AttributesImpl class copied from old StAXReader. This class is used to implement 318 * getAttributes() on a StAX Reader. 319 */ 320 public static class AttributesImpl implements Attributes { 321 322 static final String XMLNS_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/"; 323 324 static class AttributeInfo { 325 326 private QName name; 327 private String value; 328 329 public AttributeInfo(QName name, String value) { 330 this.name = name; 331 if (value == null) { 332 // e.g., <return xmlns=""> -- stax returns null 333 this.value = ""; 334 } else { 335 this.value = value; 336 } 337 } 338 339 QName getName() { 340 return name; 341 } 342 343 String getValue() { 344 return value; 345 } 346 347 /* 348 * Return "xmlns:" as part of name if namespace. 349 */ 350 String getLocalName() { 351 if (isNamespaceDeclaration()) { 352 if (name.getLocalPart().equals("")) { 353 return "xmlns"; 354 } 355 return "xmlns:" + name.getLocalPart(); 356 } 357 return name.getLocalPart(); 358 } 359 360 boolean isNamespaceDeclaration() { 361 return (name.getNamespaceURI() == XMLNS_NAMESPACE_URI); 362 } 363 } 364 365 // stores qname and value for each attribute 366 AttributeInfo [] atInfos; 367 368 /* 369 * Will create a list that contains the namespace declarations 370 * as well as the other attributes. 371 */ 372 public AttributesImpl(XMLStreamReader reader) { 373 if (reader == null) { 374 375 // this is the case when we call getAttributes() on the 376 // reader when it is not on a start tag 377 atInfos = new AttributeInfo[0]; 378 } else { 379 380 // this is the normal case 381 int index = 0; 382 int namespaceCount = reader.getNamespaceCount(); 383 int attributeCount = reader.getAttributeCount(); 384 atInfos = new AttributeInfo[namespaceCount + attributeCount]; 385 for (int i=0; i<namespaceCount; i++) { 386 String namespacePrefix = reader.getNamespacePrefix(i); 387 388 // will be null if default prefix. QName can't take null 389 if (namespacePrefix == null) { 390 namespacePrefix = ""; 391 } 392 atInfos[index++] = new AttributeInfo( 393 new QName(XMLNS_NAMESPACE_URI, 394 namespacePrefix, 395 "xmlns"), 396 reader.getNamespaceURI(i)); 397 } 398 for (int i=0; i<attributeCount; i++) { 399 atInfos[index++] = new AttributeInfo( 400 reader.getAttributeName(i), 401 reader.getAttributeValue(i)); 402 } 403 } 404 } 405 406 public int getLength() { 407 return atInfos.length; 408 } 409 410 public String getLocalName(int index) { 411 if (index >= 0 && index < atInfos.length) { 412 return atInfos[index].getLocalName(); 413 } 414 return null; 415 } 416 417 public QName getName(int index) { 418 if (index >= 0 && index < atInfos.length) { 419 return atInfos[index].getName(); 420 } 421 return null; 422 } 423 424 public String getPrefix(int index) { 425 if (index >= 0 && index < atInfos.length) { 426 return atInfos[index].getName().getPrefix(); 427 } 428 return null; 429 } 430 431 public String getURI(int index) { 432 if (index >= 0 && index < atInfos.length) { 433 return atInfos[index].getName().getNamespaceURI(); 434 } 435 return null; 436 } 437 438 public String getValue(int index) { 439 if (index >= 0 && index < atInfos.length) { 440 return atInfos[index].getValue(); 441 } 442 return null; 443 } 444 445 public String getValue(QName name) { 446 int index = getIndex(name); 447 if (index != -1) { 448 return atInfos[index].getValue(); 449 } 450 return null; 451 } 452 453 public String getValue(String localName) { 454 int index = getIndex(localName); 455 if (index != -1) { 456 return atInfos[index].getValue(); 457 } 458 return null; 459 } 460 461 public String getValue(String uri, String localName) { 462 int index = getIndex(uri, localName); 463 if (index != -1) { 464 return atInfos[index].getValue(); 465 } 466 return null; 467 } 468 469 public boolean isNamespaceDeclaration(int index) { 470 if (index >= 0 && index < atInfos.length) { 471 return atInfos[index].isNamespaceDeclaration(); 472 } 473 return false; 474 } 475 476 public int getIndex(QName name) { 477 for (int i=0; i<atInfos.length; i++) { 478 if (atInfos[i].getName().equals(name)) { 479 return i; 480 } 481 } 482 return -1; 483 } 484 485 public int getIndex(String localName) { 486 for (int i=0; i<atInfos.length; i++) { 487 if (atInfos[i].getName().getLocalPart().equals(localName)) { 488 return i; 489 } 490 } 491 return -1; 492 } 493 494 public int getIndex(String uri, String localName) { 495 QName qName; 496 for (int i=0; i<atInfos.length; i++) { 497 qName = atInfos[i].getName(); 498 if (qName.getNamespaceURI().equals(uri) && 499 qName.getLocalPart().equals(localName)) { 500 501 return i; 502 } 503 } 504 return -1; 505 } 506 } 507} 508