001package ca.uhn.fhir.parser; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2016 University Health Network 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022import static org.apache.commons.lang3.StringUtils.defaultString; 023import static org.apache.commons.lang3.StringUtils.isBlank; 024import static org.apache.commons.lang3.StringUtils.isNotBlank; 025 026import java.io.IOException; 027import java.io.Reader; 028import java.io.StringWriter; 029import java.io.Writer; 030import java.util.ArrayList; 031import java.util.Iterator; 032import java.util.List; 033 034import javax.xml.namespace.QName; 035import javax.xml.stream.FactoryConfigurationError; 036import javax.xml.stream.XMLEventReader; 037import javax.xml.stream.XMLStreamConstants; 038import javax.xml.stream.XMLStreamException; 039import javax.xml.stream.XMLStreamWriter; 040import javax.xml.stream.events.Attribute; 041import javax.xml.stream.events.Characters; 042import javax.xml.stream.events.Comment; 043import javax.xml.stream.events.EntityReference; 044import javax.xml.stream.events.Namespace; 045import javax.xml.stream.events.StartElement; 046import javax.xml.stream.events.XMLEvent; 047 048import org.apache.commons.lang3.StringUtils; 049import org.hl7.fhir.instance.model.api.IAnyResource; 050import org.hl7.fhir.instance.model.api.IBase; 051import org.hl7.fhir.instance.model.api.IBaseBinary; 052import org.hl7.fhir.instance.model.api.IBaseDatatype; 053import org.hl7.fhir.instance.model.api.IBaseExtension; 054import org.hl7.fhir.instance.model.api.IBaseHasExtensions; 055import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions; 056import org.hl7.fhir.instance.model.api.IBaseReference; 057import org.hl7.fhir.instance.model.api.IBaseResource; 058import org.hl7.fhir.instance.model.api.IBaseXhtml; 059import org.hl7.fhir.instance.model.api.IDomainResource; 060import org.hl7.fhir.instance.model.api.IIdType; 061import org.hl7.fhir.instance.model.api.INarrative; 062import org.hl7.fhir.instance.model.api.IPrimitiveType; 063 064import ca.uhn.fhir.context.BaseRuntimeChildDefinition; 065import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; 066import ca.uhn.fhir.context.BaseRuntimeElementDefinition; 067import ca.uhn.fhir.context.ConfigurationException; 068import ca.uhn.fhir.context.FhirContext; 069import ca.uhn.fhir.context.FhirVersionEnum; 070import ca.uhn.fhir.context.RuntimeChildContainedResources; 071import ca.uhn.fhir.context.RuntimeChildDeclaredExtensionDefinition; 072import ca.uhn.fhir.context.RuntimeChildNarrativeDefinition; 073import ca.uhn.fhir.context.RuntimeChildUndeclaredExtensionDefinition; 074import ca.uhn.fhir.context.RuntimeResourceDefinition; 075import ca.uhn.fhir.model.api.Bundle; 076import ca.uhn.fhir.model.api.BundleEntry; 077import ca.uhn.fhir.model.api.IResource; 078import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions; 079import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; 080import ca.uhn.fhir.model.api.Tag; 081import ca.uhn.fhir.model.api.TagList; 082import ca.uhn.fhir.model.base.composite.BaseCodingDt; 083import ca.uhn.fhir.model.base.composite.BaseNarrativeDt; 084import ca.uhn.fhir.model.primitive.IdDt; 085import ca.uhn.fhir.model.primitive.InstantDt; 086import ca.uhn.fhir.model.primitive.StringDt; 087import ca.uhn.fhir.model.primitive.XhtmlDt; 088import ca.uhn.fhir.narrative.INarrativeGenerator; 089import ca.uhn.fhir.rest.server.Constants; 090import ca.uhn.fhir.rest.server.EncodingEnum; 091import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; 092import ca.uhn.fhir.util.ElementUtil; 093import ca.uhn.fhir.util.NonPrettyPrintWriterWrapper; 094import ca.uhn.fhir.util.PrettyPrintWriterWrapper; 095import ca.uhn.fhir.util.XmlUtil; 096 097/** 098 * This class is the FHIR XML parser/encoder. Users should not interact with this class directly, but should use {@link FhirContext#newXmlParser()} to get an instance. 099 */ 100public class XmlParser extends BaseParser implements IParser { 101 102 static final String ATOM_NS = "http://www.w3.org/2005/Atom"; 103 static final String FHIR_NS = "http://hl7.org/fhir"; 104 static final String OPENSEARCH_NS = "http://a9.com/-/spec/opensearch/1.1/"; 105 private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParser.class); 106 static final String RESREF_DISPLAY = "display"; 107 static final String RESREF_REFERENCE = "reference"; 108 static final String TOMBSTONES_NS = "http://purl.org/atompub/tombstones/1.0"; 109 static final String XHTML_NS = "http://www.w3.org/1999/xhtml"; 110 111 // private static final Set<String> RESOURCE_NAMESPACES; 112 113 private FhirContext myContext; 114 private boolean myPrettyPrint; 115 116 /** 117 * Do not use this constructor, the recommended way to obtain a new instance of the XML parser is to invoke {@link FhirContext#newXmlParser()}. 118 * 119 * @param theParserErrorHandler 120 */ 121 public XmlParser(FhirContext theContext, IParserErrorHandler theParserErrorHandler) { 122 super(theContext, theParserErrorHandler); 123 myContext = theContext; 124 } 125 126 private XMLEventReader createStreamReader(Reader theReader) { 127 try { 128 return XmlUtil.createXmlReader(theReader); 129 } catch (FactoryConfigurationError e1) { 130 throw new ConfigurationException("Failed to initialize STaX event factory", e1); 131 } catch (XMLStreamException e1) { 132 throw new DataFormatException(e1); 133 } 134 135 // XMLEventReader streamReader; 136 // try { 137 // streamReader = myXmlInputFactory.createXMLEventReader(theReader); 138 // } catch (XMLStreamException e) { 139 // throw new DataFormatException(e); 140 // } catch (FactoryConfigurationError e) { 141 // throw new ConfigurationException("Failed to initialize STaX event factory", e); 142 // } 143 // return streamReader; 144 } 145 146 private XMLStreamWriter createXmlWriter(Writer theWriter) throws XMLStreamException { 147 XMLStreamWriter eventWriter; 148 eventWriter = XmlUtil.createXmlStreamWriter(theWriter); 149 eventWriter = decorateStreamWriter(eventWriter); 150 return eventWriter; 151 } 152 153 private XMLStreamWriter decorateStreamWriter(XMLStreamWriter eventWriter) { 154 if (myPrettyPrint) { 155 PrettyPrintWriterWrapper retVal = new PrettyPrintWriterWrapper(eventWriter); 156 return retVal; 157 } else { 158 NonPrettyPrintWriterWrapper retVal = new NonPrettyPrintWriterWrapper(eventWriter); 159 return retVal; 160 } 161 } 162 163 @Override 164 public void doEncodeBundleToWriter(Bundle theBundle, Writer theWriter) throws DataFormatException { 165 try { 166 XMLStreamWriter eventWriter = createXmlWriter(theWriter); 167 if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) { 168 encodeBundleToWriterDstu2(theBundle, eventWriter); 169 } else { 170 encodeBundleToWriterDstu1(theBundle, eventWriter); 171 } 172 } catch (XMLStreamException e) { 173 throw new ConfigurationException("Failed to initialize STaX event factory", e); 174 } 175 } 176 177 @Override 178 public void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws DataFormatException { 179 XMLStreamWriter eventWriter; 180 try { 181 eventWriter = createXmlWriter(theWriter); 182 183 encodeResourceToXmlStreamWriter(theResource, eventWriter, false); 184 eventWriter.flush(); 185 } catch (XMLStreamException e) { 186 throw new ConfigurationException("Failed to initialize STaX event factory", e); 187 } 188 } 189 190 @Override 191 public <T extends IBaseResource> T doParseResource(Class<T> theResourceType, Reader theReader) { 192 XMLEventReader streamReader = createStreamReader(theReader); 193 return parseResource(theResourceType, streamReader); 194 } 195 196 private <T> T doXmlLoop(XMLEventReader streamReader, ParserState<T> parserState) { 197 ourLog.trace("Entering XML parsing loop with state: {}", parserState); 198 199 try { 200 while (streamReader.hasNext()) { 201 XMLEvent nextEvent = streamReader.nextEvent(); 202 try { 203 if (nextEvent.isStartElement()) { 204 StartElement elem = nextEvent.asStartElement(); 205 206 String namespaceURI = elem.getName().getNamespaceURI(); 207 208 if ("extension".equals(elem.getName().getLocalPart())) { 209 Attribute urlAttr = elem.getAttributeByName(new QName("url")); 210 if (urlAttr == null || isBlank(urlAttr.getValue())) { 211 throw new DataFormatException("Extension element has no 'url' attribute"); 212 } 213 parserState.enteringNewElementExtension(elem, urlAttr.getValue(), false); 214 } else if ("modifierExtension".equals(elem.getName().getLocalPart())) { 215 Attribute urlAttr = elem.getAttributeByName(new QName("url")); 216 if (urlAttr == null || isBlank(urlAttr.getValue())) { 217 throw new DataFormatException("Extension element has no 'url' attribute"); 218 } 219 parserState.enteringNewElementExtension(elem, urlAttr.getValue(), true); 220 } else { 221 222 String elementName = elem.getName().getLocalPart(); 223 parserState.enteringNewElement(namespaceURI, elementName); 224 225 } 226 227 @SuppressWarnings("unchecked") 228 Iterator<Attribute> attributes = elem.getAttributes(); 229 for (Iterator<Attribute> iter = attributes; iter.hasNext();) { 230 Attribute next = iter.next(); 231 parserState.attributeValue(next.getName().getLocalPart(), next.getValue()); 232 } 233 234 } else if (nextEvent.isAttribute()) { 235 Attribute elem = (Attribute) nextEvent; 236 String name = (elem.getName().getLocalPart()); 237 parserState.attributeValue(name, elem.getValue()); 238 } else if (nextEvent.isEndElement()) { 239 parserState.endingElement(); 240 if (parserState.isComplete()) { 241 return parserState.getObject(); 242 } 243 } else if (nextEvent.isCharacters()) { 244 parserState.string(nextEvent.asCharacters().getData()); 245 } 246 247 parserState.xmlEvent(nextEvent); 248 249 } catch (DataFormatException e) { 250 throw new DataFormatException("DataFormatException at [" + nextEvent.getLocation().toString() + "]: " + e.getMessage(), e); 251 } 252 } 253 return null; 254 } catch (XMLStreamException e) { 255 throw new DataFormatException(e); 256 } 257 } 258 259 @Override 260 public String encodeBundleToString(Bundle theBundle) throws DataFormatException { 261 StringWriter stringWriter = new StringWriter(); 262 try { 263 encodeBundleToWriter(theBundle, stringWriter); 264 } catch (IOException e) { 265 throw new InternalErrorException("IOException writing to StringWriter - Should not happen", e); 266 } 267 268 return stringWriter.toString(); 269 } 270 271 private void encodeBundleToWriterDstu1(Bundle theBundle, XMLStreamWriter eventWriter) throws XMLStreamException { 272 eventWriter.writeStartElement("feed"); 273 eventWriter.writeDefaultNamespace(ATOM_NS); 274 275 writeTagWithTextNode(eventWriter, "title", theBundle.getTitle()); 276 writeTagWithTextNode(eventWriter, "id", theBundle.getBundleId()); 277 278 writeAtomLink(eventWriter, Constants.LINK_SELF, theBundle.getLinkSelf()); 279 writeAtomLink(eventWriter, Constants.LINK_FIRST, theBundle.getLinkFirst()); 280 writeAtomLink(eventWriter, Constants.LINK_PREVIOUS, theBundle.getLinkPrevious()); 281 writeAtomLink(eventWriter, Constants.LINK_NEXT, theBundle.getLinkNext()); 282 writeAtomLink(eventWriter, Constants.LINK_LAST, theBundle.getLinkLast()); 283 writeAtomLink(eventWriter, Constants.LINK_FHIR_BASE, theBundle.getLinkBase()); 284 285 if (theBundle.getTotalResults().getValue() != null) { 286 eventWriter.writeStartElement("os", "totalResults", OPENSEARCH_NS); 287 eventWriter.writeNamespace("os", OPENSEARCH_NS); 288 eventWriter.writeCharacters(theBundle.getTotalResults().getValue().toString()); 289 eventWriter.writeEndElement(); 290 } 291 292 writeOptionalTagWithTextNode(eventWriter, "updated", theBundle.getUpdated()); 293 294 if (StringUtils.isNotBlank(theBundle.getAuthorName().getValue())) { 295 eventWriter.writeStartElement("author"); 296 writeTagWithTextNode(eventWriter, "name", theBundle.getAuthorName()); 297 writeOptionalTagWithTextNode(eventWriter, "uri", theBundle.getAuthorUri()); 298 eventWriter.writeEndElement(); 299 } 300 301 writeCategories(eventWriter, theBundle.getCategories()); 302 303 for (BundleEntry nextEntry : theBundle.getEntries()) { 304 boolean deleted = false; 305 if (nextEntry.getDeletedAt() != null && nextEntry.getDeletedAt().isEmpty() == false) { 306 deleted = true; 307 eventWriter.writeStartElement("at", "deleted-entry", TOMBSTONES_NS); 308 eventWriter.writeNamespace("at", TOMBSTONES_NS); 309 310 if (nextEntry.getDeletedResourceId().isEmpty()) { 311 writeOptionalAttribute(eventWriter, "ref", nextEntry.getId().getValueAsString()); 312 } else { 313 writeOptionalAttribute(eventWriter, "ref", nextEntry.getDeletedResourceId().getValueAsString()); 314 } 315 316 writeOptionalAttribute(eventWriter, "when", nextEntry.getDeletedAt().getValueAsString()); 317 if (nextEntry.getDeletedByEmail().isEmpty() == false || nextEntry.getDeletedByName().isEmpty() == false) { 318 eventWriter.writeStartElement(TOMBSTONES_NS, "by"); 319 if (nextEntry.getDeletedByName().isEmpty() == false) { 320 eventWriter.writeStartElement(TOMBSTONES_NS, "name"); 321 eventWriter.writeCharacters(nextEntry.getDeletedByName().getValue()); 322 eventWriter.writeEndElement(); 323 } 324 if (nextEntry.getDeletedByEmail().isEmpty() == false) { 325 eventWriter.writeStartElement(TOMBSTONES_NS, "email"); 326 eventWriter.writeCharacters(nextEntry.getDeletedByEmail().getValue()); 327 eventWriter.writeEndElement(); 328 } 329 eventWriter.writeEndElement(); 330 } 331 if (nextEntry.getDeletedComment().isEmpty() == false) { 332 eventWriter.writeStartElement(TOMBSTONES_NS, "comment"); 333 eventWriter.writeCharacters(nextEntry.getDeletedComment().getValue()); 334 eventWriter.writeEndElement(); 335 } 336 } else { 337 eventWriter.writeStartElement("entry"); 338 } 339 340 writeOptionalTagWithTextNode(eventWriter, "title", nextEntry.getTitle()); 341 if (!deleted) { 342 if (nextEntry.getId().isEmpty() == false) { 343 writeTagWithTextNode(eventWriter, "id", nextEntry.getId()); 344 } else { 345 writeTagWithTextNode(eventWriter, "id", nextEntry.getResource().getId()); 346 } 347 } 348 writeOptionalTagWithTextNode(eventWriter, "updated", nextEntry.getUpdated()); 349 writeOptionalTagWithTextNode(eventWriter, "published", nextEntry.getPublished()); 350 351 writeCategories(eventWriter, nextEntry.getCategories()); 352 353 if (!nextEntry.getLinkSelf().isEmpty()) { 354 writeAtomLink(eventWriter, "self", nextEntry.getLinkSelf()); 355 } 356 357 if (!nextEntry.getLinkAlternate().isEmpty()) { 358 writeAtomLink(eventWriter, "alternate", nextEntry.getLinkAlternate()); 359 } 360 361 if (!nextEntry.getLinkSearch().isEmpty()) { 362 writeAtomLink(eventWriter, "search", nextEntry.getLinkSearch()); 363 } 364 365 IResource resource = nextEntry.getResource(); 366 if (resource != null && !resource.isEmpty() && !deleted) { 367 eventWriter.writeStartElement("content"); 368 eventWriter.writeAttribute("type", "text/xml"); 369 encodeResourceToXmlStreamWriter(resource, eventWriter, false); 370 eventWriter.writeEndElement(); // content 371 } else { 372 ourLog.debug("Bundle entry contains null resource"); 373 } 374 375 if (!nextEntry.getSummary().isEmpty()) { 376 eventWriter.writeStartElement("summary"); 377 eventWriter.writeAttribute("type", "xhtml"); 378 encodeXhtml(nextEntry.getSummary(), eventWriter); 379 eventWriter.writeEndElement(); 380 } 381 382 eventWriter.writeEndElement(); // entry 383 } 384 385 eventWriter.writeEndElement(); 386 eventWriter.close(); 387 } 388 389 private void encodeBundleToWriterDstu2(Bundle theBundle, XMLStreamWriter theEventWriter) throws XMLStreamException { 390 theEventWriter.writeStartElement("Bundle"); 391 theEventWriter.writeDefaultNamespace(FHIR_NS); 392 393 writeOptionalTagWithValue(theEventWriter, "id", theBundle.getId().getIdPart()); 394 395 InstantDt updated = (InstantDt) theBundle.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); 396 IdDt bundleId = theBundle.getId(); 397 if (bundleId != null && isNotBlank(bundleId.getVersionIdPart()) || (updated != null && !updated.isEmpty())) { 398 theEventWriter.writeStartElement("meta"); 399 writeOptionalTagWithValue(theEventWriter, "versionId", bundleId.getVersionIdPart()); 400 if (updated != null) { 401 writeOptionalTagWithValue(theEventWriter, "lastUpdated", updated.getValueAsString()); 402 } 403 theEventWriter.writeEndElement(); 404 } 405 406 String bundleBaseUrl = theBundle.getLinkBase().getValue(); 407 408 writeOptionalTagWithValue(theEventWriter, "type", theBundle.getType().getValue()); 409 writeOptionalTagWithValue(theEventWriter, "total", theBundle.getTotalResults().getValueAsString()); 410 411 writeBundleResourceLink(theEventWriter, "first", theBundle.getLinkFirst()); 412 writeBundleResourceLink(theEventWriter, "previous", theBundle.getLinkPrevious()); 413 writeBundleResourceLink(theEventWriter, "next", theBundle.getLinkNext()); 414 writeBundleResourceLink(theEventWriter, "last", theBundle.getLinkLast()); 415 writeBundleResourceLink(theEventWriter, "self", theBundle.getLinkSelf()); 416 417 for (BundleEntry nextEntry : theBundle.getEntries()) { 418 theEventWriter.writeStartElement("entry"); 419 420 boolean deleted = false; 421 if (nextEntry.getDeletedAt() != null && nextEntry.getDeletedAt().isEmpty() == false) { 422 deleted = true; 423 } 424 425 writeBundleResourceLink(theEventWriter, "alternate", nextEntry.getLinkAlternate()); 426 427 if (nextEntry.getResource() != null && nextEntry.getResource().getId().getBaseUrl() != null) { 428 writeOptionalTagWithValue(theEventWriter, "fullUrl", nextEntry.getResource().getId().getValue()); 429 } 430 431 IResource resource = nextEntry.getResource(); 432 if (resource != null && !resource.isEmpty() && !deleted) { 433 theEventWriter.writeStartElement("resource"); 434 encodeResourceToXmlStreamWriter(resource, theEventWriter, false); 435 theEventWriter.writeEndElement(); // content 436 } else { 437 ourLog.debug("Bundle entry contains null resource"); 438 } 439 440 if (nextEntry.getSearchMode().isEmpty() == false || nextEntry.getScore().isEmpty() == false) { 441 theEventWriter.writeStartElement("search"); 442 writeOptionalTagWithValue(theEventWriter, "mode", nextEntry.getSearchMode().getValueAsString()); 443 writeOptionalTagWithValue(theEventWriter, "score", nextEntry.getScore().getValueAsString()); 444 theEventWriter.writeEndElement(); 445 // IResource nextResource = nextEntry.getResource(); 446 } 447 448 if (nextEntry.getTransactionMethod().isEmpty() == false || nextEntry.getLinkSearch().isEmpty() == false) { 449 theEventWriter.writeStartElement("request"); 450 writeOptionalTagWithValue(theEventWriter, "method", nextEntry.getTransactionMethod().getValue()); 451 writeOptionalTagWithValue(theEventWriter, "url", nextEntry.getLinkSearch().getValue()); 452 theEventWriter.writeEndElement(); 453 } 454 455 if (deleted) { 456 theEventWriter.writeStartElement("deleted"); 457 writeOptionalTagWithValue(theEventWriter, "type", nextEntry.getId().getResourceType()); 458 writeOptionalTagWithValue(theEventWriter, "id", nextEntry.getId().getIdPart()); 459 writeOptionalTagWithValue(theEventWriter, "versionId", nextEntry.getId().getVersionIdPart()); 460 writeOptionalTagWithValue(theEventWriter, "instant", nextEntry.getDeletedAt().getValueAsString()); 461 theEventWriter.writeEndElement(); 462 } 463 464 theEventWriter.writeEndElement(); // entry 465 } 466 467 theEventWriter.writeEndElement(); 468 theEventWriter.close(); 469 } 470 471 private void encodeChildElementToStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, IBase nextValue, String childName, BaseRuntimeElementDefinition<?> childDef, 472 String theExtensionUrl, boolean theIncludedResource, CompositeChildElement theParent) throws XMLStreamException, DataFormatException { 473 if (nextValue == null || nextValue.isEmpty()) { 474 if (isChildContained(childDef, theIncludedResource)) { 475 // We still want to go in.. 476 } else { 477 return; 478 } 479 } 480 481 switch (childDef.getChildType()) { 482 case ID_DATATYPE: { 483 IIdType value = (IIdType) nextValue; 484 String encodedValue = "id".equals(childName) ? value.getIdPart() : value.getValue(); 485 if (value != null) { 486 theEventWriter.writeStartElement(childName); 487 theEventWriter.writeAttribute("value", encodedValue); 488 encodeExtensionsIfPresent(theResource, theEventWriter, nextValue, theIncludedResource); 489 theEventWriter.writeEndElement(); 490 } 491 break; 492 } 493 case PRIMITIVE_DATATYPE: { 494 IPrimitiveType<?> pd = (IPrimitiveType<?>) nextValue; 495 String value = pd.getValueAsString(); 496 if (value != null) { 497 theEventWriter.writeStartElement(childName); 498 theEventWriter.writeAttribute("value", value); 499 encodeExtensionsIfPresent(theResource, theEventWriter, nextValue, theIncludedResource); 500 theEventWriter.writeEndElement(); 501 } 502 break; 503 } 504 case RESOURCE_BLOCK: 505 case COMPOSITE_DATATYPE: { 506 theEventWriter.writeStartElement(childName); 507 if (isNotBlank(theExtensionUrl)) { 508 theEventWriter.writeAttribute("url", theExtensionUrl); 509 } 510 BaseRuntimeElementCompositeDefinition<?> childCompositeDef = (BaseRuntimeElementCompositeDefinition<?>) childDef; 511 encodeCompositeElementToStreamWriter(theResource, nextValue, theEventWriter, childCompositeDef, theIncludedResource, theParent); 512 theEventWriter.writeEndElement(); 513 break; 514 } 515 case RESOURCE_REF: { 516 IBaseReference ref = (IBaseReference) nextValue; 517 if (!ref.isEmpty()) { 518 theEventWriter.writeStartElement(childName); 519 encodeResourceReferenceToStreamWriter(theEventWriter, ref, theResource, theIncludedResource); 520 theEventWriter.writeEndElement(); 521 } 522 break; 523 } 524 case CONTAINED_RESOURCE_LIST: 525 case CONTAINED_RESOURCES: { 526 /* 527 * Disable per #103 for (IResource next : value.getContainedResources()) { if (getContainedResources().getResourceId(next) != null) { continue; } 528 * theEventWriter.writeStartElement("contained"); encodeResourceToXmlStreamWriter(next, theEventWriter, true, fixContainedResourceId(next.getId().getValue())); 529 * theEventWriter.writeEndElement(); } 530 */ 531 for (IBaseResource next : getContainedResources().getContainedResources()) { 532 IIdType resourceId = getContainedResources().getResourceId(next); 533 theEventWriter.writeStartElement("contained"); 534 encodeResourceToXmlStreamWriter(next, theEventWriter, true, fixContainedResourceId(resourceId.getValue())); 535 theEventWriter.writeEndElement(); 536 } 537 break; 538 } 539 case RESOURCE: { 540 theEventWriter.writeStartElement(childName); 541 IBaseResource resource = (IBaseResource) nextValue; 542 encodeResourceToXmlStreamWriter(resource, theEventWriter, false); 543 theEventWriter.writeEndElement(); 544 break; 545 } 546 case PRIMITIVE_XHTML: { 547 XhtmlDt dt = (XhtmlDt) nextValue; 548 if (dt.hasContent()) { 549 encodeXhtml(dt, theEventWriter); 550 } 551 break; 552 } 553 case PRIMITIVE_XHTML_HL7ORG: { 554 IBaseXhtml dt = (IBaseXhtml) nextValue; 555 if (dt.isEmpty()) { 556 break; 557 } else { 558 // TODO: this is probably not as efficient as it could be 559 XhtmlDt hdt = new XhtmlDt(); 560 hdt.setValueAsString(dt.getValueAsString()); 561 encodeXhtml(hdt, theEventWriter); 562 break; 563 } 564 } 565 case EXTENSION_DECLARED: 566 case UNDECL_EXT: { 567 throw new IllegalStateException("state should not happen: " + childDef.getName()); 568 } 569 } 570 571 } 572 573 private void encodeCompositeElementChildrenToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, List<? extends BaseRuntimeChildDefinition> theChildren, 574 boolean theContainedResource, CompositeChildElement theParent) throws XMLStreamException, DataFormatException { 575 for (CompositeChildElement nextChildElem : super.compositeChildIterator(theChildren, theContainedResource, theParent)) { 576 577 BaseRuntimeChildDefinition nextChild = nextChildElem.getDef(); 578 579 if (nextChild instanceof RuntimeChildNarrativeDefinition) { 580 INarrativeGenerator gen = myContext.getNarrativeGenerator(); 581 INarrative narr; 582 if (theResource instanceof IResource) { 583 narr = ((IResource) theResource).getText(); 584 } else if (theResource instanceof IDomainResource) { 585 narr = ((IDomainResource)theResource).getText(); 586 } else { 587 narr = null; 588 } 589 if (gen != null && narr.isEmpty()) { 590 gen.generateNarrative(myContext, theResource, narr); 591 } 592 if (narr != null && narr.isEmpty() == false) { 593 RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild; 594 String childName = nextChild.getChildNameByDatatype(child.getDatatype()); 595 BaseRuntimeElementDefinition<?> type = child.getChildByName(childName); 596 encodeChildElementToStreamWriter(theResource, theEventWriter, narr, childName, type, null, theContainedResource, nextChildElem); 597 continue; 598 } 599 } 600 601 if (nextChild instanceof RuntimeChildContainedResources) { 602 encodeChildElementToStreamWriter(theResource, theEventWriter, null, nextChild.getChildNameByDatatype(null), nextChild.getChildElementDefinitionByDatatype(null), null, theContainedResource, 603 nextChildElem); 604 } else { 605 606 List<? extends IBase> values = nextChild.getAccessor().getValues(theElement); 607 values = super.preProcessValues(nextChild, theResource, values); 608 609 if (values == null || values.isEmpty()) { 610 continue; 611 } 612 for (IBase nextValue : values) { 613 if ((nextValue == null || nextValue.isEmpty())) { 614 continue; 615 } 616 Class<? extends IBase> type = nextValue.getClass(); 617 String childName = nextChild.getChildNameByDatatype(type); 618 String extensionUrl = nextChild.getExtensionUrl(); 619 BaseRuntimeElementDefinition<?> childDef = nextChild.getChildElementDefinitionByDatatype(type); 620 if (childDef == null) { 621 super.throwExceptionForUnknownChildType(nextChild, type); 622 } 623 624 if (nextValue instanceof IBaseExtension && myContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) { 625 // This is called for the Query resource in DSTU1 only 626 extensionUrl = ((IBaseExtension<?, ?>) nextValue).getUrl(); 627 encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theContainedResource, nextChildElem); 628 629 } else if (extensionUrl != null && childName.equals("extension") == false) { 630 RuntimeChildDeclaredExtensionDefinition extDef = (RuntimeChildDeclaredExtensionDefinition) nextChild; 631 if (extDef.isModifier()) { 632 theEventWriter.writeStartElement("modifierExtension"); 633 } else { 634 theEventWriter.writeStartElement("extension"); 635 } 636 637 theEventWriter.writeAttribute("url", extensionUrl); 638 encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, null, theContainedResource, nextChildElem); 639 theEventWriter.writeEndElement(); 640 } else if (nextChild instanceof RuntimeChildNarrativeDefinition && theContainedResource) { 641 // suppress narratives from contained resources 642 } else { 643 encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theContainedResource, nextChildElem); 644 } 645 } 646 } 647 } 648 } 649 650 private void encodeCompositeElementToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> theElementDefinition, 651 boolean theIncludedResource, CompositeChildElement theParent) throws XMLStreamException, DataFormatException { 652 encodeExtensionsIfPresent(theResource, theEventWriter, theElement, theIncludedResource); 653 encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, theElementDefinition.getExtensions(), theIncludedResource, theParent); 654 encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, theElementDefinition.getChildren(), theIncludedResource, theParent); 655 } 656 657 private void encodeExtensionsIfPresent(IBaseResource theResource, XMLStreamWriter theWriter, IBase theElement, boolean theIncludedResource) throws XMLStreamException, DataFormatException { 658 if (theElement instanceof ISupportsUndeclaredExtensions) { 659 ISupportsUndeclaredExtensions res = (ISupportsUndeclaredExtensions) theElement; 660 encodeUndeclaredExtensions(theResource, theWriter, toBaseExtensionList(res.getUndeclaredExtensions()), "extension", theIncludedResource); 661 encodeUndeclaredExtensions(theResource, theWriter, toBaseExtensionList(res.getUndeclaredModifierExtensions()), "modifierExtension", theIncludedResource); 662 } 663 if (theElement instanceof IBaseHasExtensions) { 664 IBaseHasExtensions res = (IBaseHasExtensions) theElement; 665 encodeUndeclaredExtensions(theResource, theWriter, res.getExtension(), "extension", theIncludedResource); 666 } 667 if (theElement instanceof IBaseHasModifierExtensions) { 668 IBaseHasModifierExtensions res = (IBaseHasModifierExtensions) theElement; 669 encodeUndeclaredExtensions(theResource, theWriter, res.getModifierExtension(), "modifierExtension", theIncludedResource); 670 } 671 } 672 673 private void encodeResourceReferenceToStreamWriter(XMLStreamWriter theEventWriter, IBaseReference theRef, IBaseResource theResource, boolean theIncludedResource) throws XMLStreamException { 674 String reference = determineReferenceText(theRef); 675 676 encodeExtensionsIfPresent(theResource, theEventWriter, theRef, theIncludedResource); 677 678 if (StringUtils.isNotBlank(reference)) { 679 theEventWriter.writeStartElement(RESREF_REFERENCE); 680 theEventWriter.writeAttribute("value", reference); 681 theEventWriter.writeEndElement(); 682 } 683 if (!(theRef.getDisplayElement().isEmpty())) { 684 theEventWriter.writeStartElement(RESREF_DISPLAY); 685 theEventWriter.writeAttribute("value", theRef.getDisplayElement().getValue()); 686 theEventWriter.writeEndElement(); 687 } 688 } 689 690 private void encodeResourceToStreamWriterInDstu2Format(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, 691 BaseRuntimeElementCompositeDefinition<?> resDef, boolean theIncludedResource) throws XMLStreamException, DataFormatException { 692 /* 693 * DSTU2 requires extensions to come in a specific spot within the encoded content - This is a bit of a messy way to make that happen, but hopefully this won't matter as much once we use the HL7 694 * structures 695 */ 696 697 List<BaseRuntimeChildDefinition> preExtensionChildren = new ArrayList<BaseRuntimeChildDefinition>(); 698 List<BaseRuntimeChildDefinition> postExtensionChildren = new ArrayList<BaseRuntimeChildDefinition>(); 699 List<BaseRuntimeChildDefinition> children = resDef.getChildren(); 700 for (BaseRuntimeChildDefinition next : children) { 701 if (next.getElementName().equals("text")) { 702 preExtensionChildren.add(next); 703 } else if (next.getElementName().equals("contained")) { 704 preExtensionChildren.add(next); 705 } else { 706 postExtensionChildren.add(next); 707 } 708 } 709 710 CompositeChildElement parent = new CompositeChildElement(theResDef); 711 712 encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, preExtensionChildren, theIncludedResource, parent); 713 714 encodeExtensionsIfPresent(theResource, theEventWriter, theElement, theIncludedResource); 715 encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, resDef.getExtensions(), theIncludedResource, parent); 716 717 encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, postExtensionChildren, theIncludedResource, parent); 718 719 } 720 721 private void encodeResourceToXmlStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, boolean theIncludedResource) throws XMLStreamException, DataFormatException { 722 String resourceId = null; 723// if (theResource instanceof IResource) { 724// // HAPI structs 725// IResource iResource = (IResource) theResource; 726// if (StringUtils.isNotBlank(iResource.getId().getIdPart())) { 727// resourceId = iResource.getId().getIdPart(); 728// } 729// } else { 730// // HL7 structs 731// IAnyResource resource = (IAnyResource) theResource; 732// if (StringUtils.isNotBlank(resource.getIdElement().getIdPart())) { 733// resourceId = resource.getIdElement().getIdPart(); 734// } 735// } 736 737 if (StringUtils.isNotBlank(theResource.getIdElement().getIdPart())) { 738 resourceId = theResource.getIdElement().getIdPart(); 739 if (theResource.getIdElement().getValue().startsWith("urn:")) { 740 resourceId = null; 741 } 742 if (myContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) { 743 resourceId = null; 744 } 745 } 746 747 if (isOmitResourceId() && !theIncludedResource) { 748 resourceId = null; 749 } 750 751 encodeResourceToXmlStreamWriter(theResource, theEventWriter, theIncludedResource, resourceId); 752 } 753 754 private void encodeResourceToXmlStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, boolean theContainedResource, String theResourceId) throws XMLStreamException { 755 if (!theContainedResource) { 756 super.containResourcesForEncoding(theResource); 757 } 758 759 RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource); 760 if (resDef == null) { 761 throw new ConfigurationException("Unknown resource type: " + theResource.getClass()); 762 } 763 764 theEventWriter.writeStartElement(resDef.getName()); 765 theEventWriter.writeDefaultNamespace(FHIR_NS); 766 767 if (theResource instanceof IAnyResource) { 768 769 // HL7.org Structures 770 writeOptionalTagWithValue(theEventWriter, "id", theResourceId); 771 encodeCompositeElementToStreamWriter(theResource, theResource, theEventWriter, resDef, theContainedResource, new CompositeChildElement(resDef)); 772 773 } else { 774 775 if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) { 776 777 // DSTU2+ 778 779 IResource resource = (IResource) theResource; 780 writeOptionalTagWithValue(theEventWriter, "id", theResourceId); 781 782 InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); 783 IdDt resourceId = resource.getId(); 784 String versionIdPart = resourceId.getVersionIdPart(); 785 if (isBlank(versionIdPart)) { 786 versionIdPart = ResourceMetadataKeyEnum.VERSION.get(resource); 787 } 788 List<BaseCodingDt> securityLabels = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.SECURITY_LABELS); 789 List<IdDt> profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES); 790 TagList tags = getMetaTagsForEncoding((resource)); 791 792 if (ElementUtil.isEmpty(versionIdPart, updated, securityLabels, tags, profiles) == false) { 793 theEventWriter.writeStartElement("meta"); 794 writeOptionalTagWithValue(theEventWriter, "versionId", versionIdPart); 795 if (updated != null) { 796 writeOptionalTagWithValue(theEventWriter, "lastUpdated", updated.getValueAsString()); 797 } 798 799 for (IdDt profile : profiles) { 800 theEventWriter.writeStartElement("profile"); 801 theEventWriter.writeAttribute("value", profile.getValue()); 802 theEventWriter.writeEndElement(); 803 } 804 for (BaseCodingDt securityLabel : securityLabels) { 805 theEventWriter.writeStartElement("security"); 806 BaseRuntimeElementCompositeDefinition<?> def = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(securityLabel.getClass()); 807 encodeCompositeElementChildrenToStreamWriter(resource, securityLabel, theEventWriter, def.getChildren(), theContainedResource, null); 808 theEventWriter.writeEndElement(); 809 } 810 if (tags != null) { 811 for (Tag tag : tags) { 812 if (tag.isEmpty()) { 813 continue; 814 } 815 theEventWriter.writeStartElement("tag"); 816 writeOptionalTagWithValue(theEventWriter, "system", tag.getScheme()); 817 writeOptionalTagWithValue(theEventWriter, "code", tag.getTerm()); 818 writeOptionalTagWithValue(theEventWriter, "display", tag.getLabel()); 819 theEventWriter.writeEndElement(); 820 } 821 } 822 theEventWriter.writeEndElement(); 823 } 824 825 if (theResource instanceof IBaseBinary) { 826 IBaseBinary bin = (IBaseBinary) theResource; 827 writeOptionalTagWithValue(theEventWriter, "contentType", bin.getContentType()); 828 writeOptionalTagWithValue(theEventWriter, "content", bin.getContentAsBase64()); 829 } else { 830 encodeResourceToStreamWriterInDstu2Format(resDef, theResource, theResource, theEventWriter, resDef, theContainedResource); 831 } 832 833 } else { 834 835 // DSTU1 836 if (theResourceId != null && theContainedResource) { 837 theEventWriter.writeAttribute("id", theResourceId); 838 } 839 840 if (theResource instanceof IBaseBinary) { 841 IBaseBinary bin = (IBaseBinary) theResource; 842 if (bin.getContentType() != null) { 843 theEventWriter.writeAttribute("contentType", bin.getContentType()); 844 } 845 theEventWriter.writeCharacters(bin.getContentAsBase64()); 846 } else { 847 encodeCompositeElementToStreamWriter(theResource, theResource, theEventWriter, resDef, theContainedResource, new CompositeChildElement(resDef)); 848 } 849 850 } 851 852 } 853 854 theEventWriter.writeEndElement(); 855 } 856 857 @Override 858 public void encodeTagListToWriter(TagList theTagList, Writer theWriter) throws IOException { 859 try { 860 XMLStreamWriter eventWriter = createXmlWriter(theWriter); 861 862 eventWriter.writeStartElement(TagList.ELEMENT_NAME_LC); 863 eventWriter.writeDefaultNamespace(FHIR_NS); 864 865 for (Tag next : theTagList) { 866 eventWriter.writeStartElement(TagList.ATTR_CATEGORY); 867 868 if (isNotBlank(next.getTerm())) { 869 eventWriter.writeAttribute(Tag.ATTR_TERM, next.getTerm()); 870 } 871 if (isNotBlank(next.getLabel())) { 872 eventWriter.writeAttribute(Tag.ATTR_LABEL, next.getLabel()); 873 } 874 if (isNotBlank(next.getScheme())) { 875 eventWriter.writeAttribute(Tag.ATTR_SCHEME, next.getScheme()); 876 } 877 878 eventWriter.writeEndElement(); 879 } 880 881 eventWriter.writeEndElement(); 882 eventWriter.close(); 883 } catch (XMLStreamException e) { 884 throw new ConfigurationException("Failed to initialize STaX event factory", e); 885 } 886 } 887 888 private void encodeUndeclaredExtensions(IBaseResource theResource, XMLStreamWriter theWriter, List<? extends IBaseExtension<?, ?>> theExtensions, String tagName, boolean theIncludedResource) 889 throws XMLStreamException, DataFormatException { 890 for (IBaseExtension<?, ?> next : theExtensions) { 891 if (next == null || (ElementUtil.isEmpty(next.getValue()) && next.getExtension().isEmpty())) { 892 continue; 893 } 894 895 theWriter.writeStartElement(tagName); 896 897 String url = next.getUrl(); 898 theWriter.writeAttribute("url", url); 899 900 if (next.getValue() != null) { 901 IBaseDatatype value = next.getValue(); 902 RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition(); 903 String childName = extDef.getChildNameByDatatype(value.getClass()); 904 BaseRuntimeElementDefinition<?> childDef; 905 if (childName == null) { 906 childDef = myContext.getElementDefinition(value.getClass()); 907 if (childDef == null) { 908 throw new ConfigurationException("Unable to encode extension, unrecognized child element type: " + value.getClass().getCanonicalName()); 909 } else { 910 childName = RuntimeChildUndeclaredExtensionDefinition.createExtensionChildName(childDef); 911 } 912 } else { 913 childDef = extDef.getChildElementDefinitionByDatatype(value.getClass()); 914 if (childDef == null) { 915 throw new ConfigurationException("Unable to encode extension, unrecognized child element type: " + value.getClass().getCanonicalName()); 916 } 917 } 918 encodeChildElementToStreamWriter(theResource, theWriter, value, childName, childDef, null, theIncludedResource, null); 919 } 920 921 // child extensions 922 encodeExtensionsIfPresent(theResource, theWriter, next, theIncludedResource); 923 924 theWriter.writeEndElement(); 925 } 926 } 927 928 private void encodeXhtml(XhtmlDt theDt, XMLStreamWriter theEventWriter) throws XMLStreamException { 929 if (theDt == null || theDt.getValue() == null) { 930 return; 931 } 932 933 boolean firstElement = true; 934 for (XMLEvent event : theDt.getValue()) { 935 switch (event.getEventType()) { 936 case XMLStreamConstants.ATTRIBUTE: 937 Attribute attr = (Attribute) event; 938 if (isBlank(attr.getName().getPrefix())) { 939 if (isBlank(attr.getName().getNamespaceURI())) { 940 theEventWriter.writeAttribute(attr.getName().getLocalPart(), attr.getValue()); 941 } else { 942 theEventWriter.writeAttribute(attr.getName().getNamespaceURI(), attr.getName().getLocalPart(), attr.getValue()); 943 } 944 } else { 945 theEventWriter.writeAttribute(attr.getName().getPrefix(), attr.getName().getNamespaceURI(), attr.getName().getLocalPart(), attr.getValue()); 946 } 947 948 break; 949 case XMLStreamConstants.CDATA: 950 theEventWriter.writeCData(((Characters) event).getData()); 951 break; 952 case XMLStreamConstants.CHARACTERS: 953 case XMLStreamConstants.SPACE: 954 String data = ((Characters) event).getData(); 955 theEventWriter.writeCharacters(data); 956 break; 957 case XMLStreamConstants.COMMENT: 958 theEventWriter.writeComment(((Comment) event).getText()); 959 break; 960 case XMLStreamConstants.END_ELEMENT: 961 theEventWriter.writeEndElement(); 962 break; 963 case XMLStreamConstants.ENTITY_REFERENCE: 964 EntityReference er = (EntityReference) event; 965 theEventWriter.writeEntityRef(er.getName()); 966 break; 967 case XMLStreamConstants.NAMESPACE: 968 Namespace ns = (Namespace) event; 969 theEventWriter.writeNamespace(ns.getPrefix(), ns.getNamespaceURI()); 970 break; 971 case XMLStreamConstants.START_ELEMENT: 972 StartElement se = event.asStartElement(); 973 if (firstElement) { 974 if (StringUtils.isBlank(se.getName().getPrefix())) { 975 String namespaceURI = se.getName().getNamespaceURI(); 976 if (StringUtils.isBlank(namespaceURI)) { 977 namespaceURI = "http://www.w3.org/1999/xhtml"; 978 } 979 theEventWriter.writeStartElement(se.getName().getLocalPart()); 980 theEventWriter.writeDefaultNamespace(namespaceURI); 981 } else { 982 String prefix = se.getName().getPrefix(); 983 String namespaceURI = se.getName().getNamespaceURI(); 984 theEventWriter.writeStartElement(prefix, se.getName().getLocalPart(), namespaceURI); 985 theEventWriter.writeNamespace(prefix, namespaceURI); 986 } 987 firstElement = false; 988 } else { 989 if (isBlank(se.getName().getPrefix())) { 990 if (isBlank(se.getName().getNamespaceURI())) { 991 theEventWriter.writeStartElement(se.getName().getLocalPart()); 992 } else { 993 if (StringUtils.isBlank(se.getName().getPrefix())) { 994 theEventWriter.writeStartElement(se.getName().getLocalPart()); 995 // theEventWriter.writeDefaultNamespace(se.getName().getNamespaceURI()); 996 } else { 997 theEventWriter.writeStartElement(se.getName().getNamespaceURI(), se.getName().getLocalPart()); 998 } 999 } 1000 } else { 1001 theEventWriter.writeStartElement(se.getName().getPrefix(), se.getName().getLocalPart(), se.getName().getNamespaceURI()); 1002 } 1003 for (Iterator<?> attrIter = se.getAttributes(); attrIter.hasNext();) { 1004 Attribute next = (Attribute) attrIter.next(); 1005 theEventWriter.writeAttribute(next.getName().getLocalPart(), next.getValue()); 1006 } 1007 } 1008 break; 1009 case XMLStreamConstants.DTD: 1010 case XMLStreamConstants.END_DOCUMENT: 1011 case XMLStreamConstants.ENTITY_DECLARATION: 1012 case XMLStreamConstants.NOTATION_DECLARATION: 1013 case XMLStreamConstants.PROCESSING_INSTRUCTION: 1014 case XMLStreamConstants.START_DOCUMENT: 1015 break; 1016 } 1017 1018 } 1019 } 1020 1021 @Override 1022 public EncodingEnum getEncoding() { 1023 return EncodingEnum.XML; 1024 } 1025 1026 @Override 1027 public <T extends IBaseResource> Bundle parseBundle(Class<T> theResourceType, Reader theReader) { 1028 XMLEventReader streamReader = createStreamReader(theReader); 1029 1030 return parseBundle(streamReader, theResourceType); 1031 } 1032 1033 private Bundle parseBundle(XMLEventReader theStreamReader, Class<? extends IBaseResource> theResourceType) { 1034 ParserState<Bundle> parserState = ParserState.getPreAtomInstance(myContext, theResourceType, false, getErrorHandler()); 1035 return doXmlLoop(theStreamReader, parserState); 1036 } 1037 1038 private <T extends IBaseResource> T parseResource(Class<T> theResourceType, XMLEventReader theStreamReader) { 1039 ParserState<T> parserState = ParserState.getPreResourceInstance(theResourceType, myContext, false, getErrorHandler()); 1040 return doXmlLoop(theStreamReader, parserState); 1041 } 1042 1043 @Override 1044 public TagList parseTagList(Reader theReader) { 1045 XMLEventReader streamReader = createStreamReader(theReader); 1046 1047 ParserState<TagList> parserState = ParserState.getPreTagListInstance(myContext, false, getErrorHandler()); 1048 return doXmlLoop(streamReader, parserState); 1049 } 1050 1051 @Override 1052 public IParser setPrettyPrint(boolean thePrettyPrint) { 1053 myPrettyPrint = thePrettyPrint; 1054 return this; 1055 } 1056 1057 /** 1058 * This is just to work around the fact that casting java.util.List<ca.uhn.fhir.model.api.ExtensionDt> to java.util.List<? extends org.hl7.fhir.instance.model.api.IBaseExtension<?, ?>> seems to be 1059 * rejected by the compiler some of the time. 1060 */ 1061 private <Q extends IBaseExtension<?, ?>> List<IBaseExtension<?, ?>> toBaseExtensionList(final List<Q> theList) { 1062 List<IBaseExtension<?, ?>> retVal = new ArrayList<IBaseExtension<?, ?>>(theList.size()); 1063 retVal.addAll(theList); 1064 return retVal; 1065 } 1066 1067 private void writeAtomLink(XMLStreamWriter theEventWriter, String theRel, StringDt theStringDt) throws XMLStreamException { 1068 if (StringUtils.isNotBlank(theStringDt.getValue())) { 1069 theEventWriter.writeStartElement("link"); 1070 theEventWriter.writeAttribute("rel", theRel); 1071 theEventWriter.writeAttribute("href", theStringDt.getValue()); 1072 theEventWriter.writeEndElement(); 1073 } 1074 } 1075 1076 private void writeBundleResourceLink(XMLStreamWriter theEventWriter, String theRel, StringDt theUrl) throws XMLStreamException { 1077 if (theUrl.isEmpty() == false) { 1078 theEventWriter.writeStartElement("link"); 1079 theEventWriter.writeStartElement("relation"); 1080 theEventWriter.writeAttribute("value", theRel); 1081 theEventWriter.writeEndElement(); 1082 theEventWriter.writeStartElement("url"); 1083 theEventWriter.writeAttribute("value", theUrl.getValue()); 1084 theEventWriter.writeEndElement(); 1085 theEventWriter.writeEndElement(); 1086 } 1087 } 1088 1089 private void writeCategories(XMLStreamWriter eventWriter, TagList categories) throws XMLStreamException { 1090 if (categories != null) { 1091 for (Tag next : categories) { 1092 eventWriter.writeStartElement("category"); 1093 eventWriter.writeAttribute("term", defaultString(next.getTerm())); 1094 eventWriter.writeAttribute("label", defaultString(next.getLabel())); 1095 eventWriter.writeAttribute("scheme", defaultString(next.getScheme())); 1096 eventWriter.writeEndElement(); 1097 } 1098 } 1099 } 1100 1101 private void writeOptionalAttribute(XMLStreamWriter theEventWriter, String theName, String theValue) throws XMLStreamException { 1102 if (StringUtils.isNotBlank(theValue)) { 1103 theEventWriter.writeAttribute(theName, theValue); 1104 } 1105 } 1106 1107 private void writeOptionalTagWithTextNode(XMLStreamWriter theEventWriter, String theTagName, InstantDt theInstantDt) throws XMLStreamException { 1108 if (theInstantDt.getValue() != null) { 1109 theEventWriter.writeStartElement(theTagName); 1110 theEventWriter.writeCharacters(theInstantDt.getValueAsString()); 1111 theEventWriter.writeEndElement(); 1112 } 1113 } 1114 1115 private void writeOptionalTagWithTextNode(XMLStreamWriter theEventWriter, String theElementName, StringDt theTextValue) throws XMLStreamException { 1116 if (StringUtils.isNotBlank(theTextValue.getValue())) { 1117 theEventWriter.writeStartElement(theElementName); 1118 theEventWriter.writeCharacters(theTextValue.getValue()); 1119 theEventWriter.writeEndElement(); 1120 } 1121 } 1122 1123 private void writeOptionalTagWithValue(XMLStreamWriter theEventWriter, String theName, String theValue) throws XMLStreamException { 1124 if (StringUtils.isNotBlank(theValue)) { 1125 theEventWriter.writeStartElement(theName); 1126 theEventWriter.writeAttribute("value", theValue); 1127 theEventWriter.writeEndElement(); 1128 } 1129 } 1130 1131 private void writeTagWithTextNode(XMLStreamWriter theEventWriter, String theElementName, IdDt theIdDt) throws XMLStreamException { 1132 theEventWriter.writeStartElement(theElementName); 1133 if (StringUtils.isNotBlank(theIdDt.getValue())) { 1134 theEventWriter.writeCharacters(theIdDt.getValue()); 1135 } 1136 theEventWriter.writeEndElement(); 1137 } 1138 1139 private void writeTagWithTextNode(XMLStreamWriter theEventWriter, String theElementName, StringDt theStringDt) throws XMLStreamException { 1140 theEventWriter.writeStartElement(theElementName); 1141 if (StringUtils.isNotBlank(theStringDt.getValue())) { 1142 theEventWriter.writeCharacters(theStringDt.getValue()); 1143 } 1144 theEventWriter.writeEndElement(); 1145 } 1146 1147}