Allow parsing of RSQuot

This commit is contained in:
James 2017-01-29 15:49:10 -05:00
parent 97f1e55131
commit b66aa9761e
4 changed files with 37 additions and 7 deletions

View File

@ -38,7 +38,7 @@ package org.hl7.fhir.utilities.xhtml;
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@ -48,7 +48,6 @@ package org.hl7.fhir.utilities.xhtml;
* #L% * #L%
*/ */
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
@ -378,10 +377,12 @@ public class XhtmlParser {
} }
return result; return result;
} }
public XhtmlDocument parse(String source, String entryName) throws FHIRFormatError, IOException { public XhtmlDocument parse(String source, String entryName) throws FHIRFormatError, IOException {
rdr = new StringReader(source); rdr = new StringReader(source);
return parse(entryName); return parse(entryName);
} }
private void parseAttributes(XhtmlNode node) throws FHIRFormatError, IOException { private void parseAttributes(XhtmlNode node) throws FHIRFormatError, IOException {
while (Character.isWhitespace(peekChar())) while (Character.isWhitespace(peekChar()))
readChar(); readChar();
@ -410,6 +411,7 @@ public class XhtmlParser {
readChar(); readChar();
} }
} }
private String parseAttributeValue(char term) throws IOException, FHIRFormatError { private String parseAttributeValue(char term) throws IOException, FHIRFormatError {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
while (peekChar() != '\0' && peekChar() != '>' && (term != '\0' || peekChar() != '/') && peekChar() != term) { while (peekChar() != '\0' && peekChar() != '>' && (term != '\0' || peekChar() != '/') && peekChar() != term) {
@ -422,6 +424,7 @@ public class XhtmlParser {
readChar(); readChar();
return b.toString(); return b.toString();
} }
private void parseElement(XhtmlNode parent, List<XhtmlNode> parents, NSMap nsm) throws IOException, FHIRFormatError { private void parseElement(XhtmlNode parent, List<XhtmlNode> parents, NSMap nsm) throws IOException, FHIRFormatError {
QName name = new QName(readName()); QName name = new QName(readName());
XhtmlNode node = parent.addTag(name.getName()); XhtmlNode node = parent.addTag(name.getName());
@ -438,6 +441,7 @@ public class XhtmlParser {
parseElementInner(node, newParents, nsm); parseElementInner(node, newParents, nsm);
} }
} }
private void parseElementInner(XhtmlNode node, List<XhtmlNode> parents, NSMap nsm) throws FHIRFormatError, IOException { private void parseElementInner(XhtmlNode node, List<XhtmlNode> parents, NSMap nsm) throws FHIRFormatError, IOException {
StringBuilder s = new StringBuilder(); StringBuilder s = new StringBuilder();
while (peekChar() != '\0' && !parents.contains(unwindPoint) && !(node == unwindPoint)) { while (peekChar() != '\0' && !parents.contains(unwindPoint) && !(node == unwindPoint)) {
@ -488,6 +492,7 @@ public class XhtmlParser {
} }
addTextNode(node, s); addTextNode(node, s);
} }
private XhtmlNode parseFragment() throws IOException, FHIRException { private XhtmlNode parseFragment() throws IOException, FHIRException {
skipWhiteSpace(); skipWhiteSpace();
if (peekChar() != '<') if (peekChar() != '<')
@ -558,6 +563,8 @@ public class XhtmlParser {
s.append(XhtmlNode.NBSP); s.append(XhtmlNode.NBSP);
else if (c.equals("amp")) else if (c.equals("amp"))
s.append('&'); s.append('&');
else if (c.equals("rsquo"))
s.append('');
else if (c.equals("gt")) else if (c.equals("gt"))
s.append('>'); s.append('>');
else if (c.equals("lt")) else if (c.equals("lt"))
@ -860,12 +867,12 @@ public class XhtmlParser {
StartElement firstEvent = (StartElement) xpp.nextEvent(); StartElement firstEvent = (StartElement) xpp.nextEvent();
res.setName(firstEvent.getSchemaType().getLocalPart()); res.setName(firstEvent.getSchemaType().getLocalPart());
for (Iterator<?> attrIter = firstEvent.getAttributes(); attrIter.hasNext(); ) { for (Iterator<?> attrIter = firstEvent.getAttributes(); attrIter.hasNext();) {
Attribute nextAttr = (Attribute) attrIter.next(); Attribute nextAttr = (Attribute) attrIter.next();
if (attributeIsOk(firstEvent.getName().getLocalPart(), nextAttr.getName().getLocalPart(), nextAttr.getValue())) if (attributeIsOk(firstEvent.getName().getLocalPart(), nextAttr.getName().getLocalPart(), nextAttr.getValue()))
res.getAttributes().put(nextAttr.getName().getLocalPart(), nextAttr.getValue()); res.getAttributes().put(nextAttr.getName().getLocalPart(), nextAttr.getValue());
} }
while (xpp.hasNext()) { while (xpp.hasNext()) {
XMLEvent nextEvent = xpp.nextEvent(); XMLEvent nextEvent = xpp.nextEvent();
int eventType = nextEvent.getEventType(); int eventType = nextEvent.getEventType();
@ -873,11 +880,11 @@ public class XhtmlParser {
break; break;
} }
if (eventType == XMLEvent.CHARACTERS) { if (eventType == XMLEvent.CHARACTERS) {
res.addText(((Characters)xpp).getData()); res.addText(((Characters) xpp).getData());
} else if (eventType == XMLEvent.COMMENT) { } else if (eventType == XMLEvent.COMMENT) {
res.addComment(((Comment)xpp).getText()); res.addComment(((Comment) xpp).getText());
} else if (eventType == XMLEvent.START_ELEMENT) { } else if (eventType == XMLEvent.START_ELEMENT) {
StartElement nextStart = (StartElement)nextEvent; StartElement nextStart = (StartElement) nextEvent;
if (elementIsOk(nextStart.getName().getLocalPart())) { if (elementIsOk(nextStart.getName().getLocalPart())) {
res.getChildNodes().add(parseNode(xpp)); res.getChildNodes().add(parseNode(xpp));
} }

View File

@ -29,6 +29,14 @@ public class XhtmlDtTest {
} }
@Test
public void testParseRsquo() {
XhtmlDt dt = new XhtmlDt();
dt.setValueAsString("It&rsquo;s January again");
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">It&rsquo;s January again</div>", dt.getValueAsString());
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">Its January again</div>", new XhtmlDt().setValue(dt.getValue()).getValueAsString());
}
@Test @Test
public void testRoundtrip() { public void testRoundtrip() {
String div = "<div xmlns=\"http://www.w3.org/1999/xhtml\"><pre>\r\n&lt;<a title=\"Prospective warnings of potential issues when providing care to the patient.\" class=\"dict\" href=\"alert-definitions.html#Alert\"><b>Alert</b></a> xmlns=&quot;http://hl7.org/fhir&quot;&gt; <span style=\"float: right\"><a title=\"Documentation for this format\" href=\"formats.html\"><img alt=\"doco\" src=\"help.png\"/></a></span>\r\n &lt;!-- from <a href=\"resources.html\">Resource</a>: <a href=\"extensibility.html\">extension</a>, <a href=\"extensibility.html#modifierExtension\">modifierExtension</a>, language, <a href=\"narrative.html#Narrative\">text</a>, and <a href=\"references.html#contained\">contained</a> --&gt;\r\n &lt;<a title=\"Identifier assigned to the alert for external use (outside the FHIR environment).\" class=\"dict\" href=\"alert-definitions.html#Alert.identifier\"><b>identifier</b></a>&gt;<span style=\"color: Gray\">&lt;!--</span> <span style=\"color: brown\"><b>0..*</b></span> <span style=\"color: darkgreen\"><a href=\"datatypes.html#Identifier\">Identifier</a></span> <span style=\"color: navy\">Business identifier</span><span style=\"color: Gray\"> --&gt;</span>&lt;/identifier&gt;\r\n &lt;<a title=\"Allows an alert to be divided into different categories like clinical, administrative etc.\" class=\"dict\" href=\"alert-definitions.html#Alert.category\"><b>category</b></a>&gt;<span style=\"color: Gray\">&lt;!--</span> <span style=\"color: brown\"><b>0..1</b></span> <span style=\"color: darkgreen\"><a href=\"datatypes.html#CodeableConcept\">CodeableConcept</a></span> <span style=\"color: navy\">Clinical, administrative, etc.</span><span style=\"color: Gray\"> --&gt;</span>&lt;/category&gt;\r\n &lt;<a title=\"Supports basic workflow.\" class=\"dict\" href=\"alert-definitions.html#Alert.status\"><b>status</b></a> value=&quot;[<span style=\"color: darkgreen\"><a href=\"datatypes.html#code\">code</a></span>]&quot;/&gt;<span style=\"color: Gray\">&lt;!--</span> <span style=\"color: brown\"><b>1..1</b></span> <span style=\"color: navy\"><a style=\"color: navy\" href=\"alert-status.html\">active | inactive | entered in error</a></span><span style=\"color: Gray\"> --&gt;</span>\r\n &lt;<a title=\"The person who this alert concerns.\" class=\"dict\" href=\"alert-definitions.html#Alert.subject\"><b>subject</b></a>&gt;<span style=\"color: Gray\">&lt;!--</span> <span style=\"color: brown\"><b>1..1</b></span> <span style=\"color: darkgreen\"><a href=\"references.html#Resource\">Resource</a>(<a href=\"patient.html#Patient\">Patient</a>)</span> <span style=\"color: navy\">Who is alert about?</span><span style=\"color: Gray\"> --&gt;</span>&lt;/subject&gt;\r\n &lt;<a title=\"The person or device that created the alert.\" class=\"dict\" href=\"alert-definitions.html#Alert.author\"><b>author</b></a>&gt;<span style=\"color: Gray\">&lt;!--</span> <span style=\"color: brown\"><b>0..1</b></span> <span style=\"color: darkgreen\"><a href=\"references.html#Resource\">Resource</a>(<a href=\"practitioner.html#Practitioner\">Practitioner</a>|<a href=\"patient.html#Patient\">Patient</a>|<a href=\"device.html#Device\">Device</a>)</span> <span style=\"color: navy\">Alert creator</span><span style=\"color: Gray\"> --&gt;</span>&lt;/author&gt;\r\n &lt;<a title=\"The textual component of the alert to display to the user.\" class=\"dict\" href=\"alert-definitions.html#Alert.note\"><b>note</b></a> value=&quot;[<span style=\"color: darkgreen\"><a href=\"datatypes.html#string\">string</a></span>]&quot;/&gt;<span style=\"color: Gray\">&lt;!--</span> <span style=\"color: brown\"><b>1..1</b></span> <span style=\"color: navy\">Text of alert</span><span style=\"color: Gray\"> --&gt;</span>\r\n&lt;/Alert&gt;\r\n</pre></div>"; String div = "<div xmlns=\"http://www.w3.org/1999/xhtml\"><pre>\r\n&lt;<a title=\"Prospective warnings of potential issues when providing care to the patient.\" class=\"dict\" href=\"alert-definitions.html#Alert\"><b>Alert</b></a> xmlns=&quot;http://hl7.org/fhir&quot;&gt; <span style=\"float: right\"><a title=\"Documentation for this format\" href=\"formats.html\"><img alt=\"doco\" src=\"help.png\"/></a></span>\r\n &lt;!-- from <a href=\"resources.html\">Resource</a>: <a href=\"extensibility.html\">extension</a>, <a href=\"extensibility.html#modifierExtension\">modifierExtension</a>, language, <a href=\"narrative.html#Narrative\">text</a>, and <a href=\"references.html#contained\">contained</a> --&gt;\r\n &lt;<a title=\"Identifier assigned to the alert for external use (outside the FHIR environment).\" class=\"dict\" href=\"alert-definitions.html#Alert.identifier\"><b>identifier</b></a>&gt;<span style=\"color: Gray\">&lt;!--</span> <span style=\"color: brown\"><b>0..*</b></span> <span style=\"color: darkgreen\"><a href=\"datatypes.html#Identifier\">Identifier</a></span> <span style=\"color: navy\">Business identifier</span><span style=\"color: Gray\"> --&gt;</span>&lt;/identifier&gt;\r\n &lt;<a title=\"Allows an alert to be divided into different categories like clinical, administrative etc.\" class=\"dict\" href=\"alert-definitions.html#Alert.category\"><b>category</b></a>&gt;<span style=\"color: Gray\">&lt;!--</span> <span style=\"color: brown\"><b>0..1</b></span> <span style=\"color: darkgreen\"><a href=\"datatypes.html#CodeableConcept\">CodeableConcept</a></span> <span style=\"color: navy\">Clinical, administrative, etc.</span><span style=\"color: Gray\"> --&gt;</span>&lt;/category&gt;\r\n &lt;<a title=\"Supports basic workflow.\" class=\"dict\" href=\"alert-definitions.html#Alert.status\"><b>status</b></a> value=&quot;[<span style=\"color: darkgreen\"><a href=\"datatypes.html#code\">code</a></span>]&quot;/&gt;<span style=\"color: Gray\">&lt;!--</span> <span style=\"color: brown\"><b>1..1</b></span> <span style=\"color: navy\"><a style=\"color: navy\" href=\"alert-status.html\">active | inactive | entered in error</a></span><span style=\"color: Gray\"> --&gt;</span>\r\n &lt;<a title=\"The person who this alert concerns.\" class=\"dict\" href=\"alert-definitions.html#Alert.subject\"><b>subject</b></a>&gt;<span style=\"color: Gray\">&lt;!--</span> <span style=\"color: brown\"><b>1..1</b></span> <span style=\"color: darkgreen\"><a href=\"references.html#Resource\">Resource</a>(<a href=\"patient.html#Patient\">Patient</a>)</span> <span style=\"color: navy\">Who is alert about?</span><span style=\"color: Gray\"> --&gt;</span>&lt;/subject&gt;\r\n &lt;<a title=\"The person or device that created the alert.\" class=\"dict\" href=\"alert-definitions.html#Alert.author\"><b>author</b></a>&gt;<span style=\"color: Gray\">&lt;!--</span> <span style=\"color: brown\"><b>0..1</b></span> <span style=\"color: darkgreen\"><a href=\"references.html#Resource\">Resource</a>(<a href=\"practitioner.html#Practitioner\">Practitioner</a>|<a href=\"patient.html#Patient\">Patient</a>|<a href=\"device.html#Device\">Device</a>)</span> <span style=\"color: navy\">Alert creator</span><span style=\"color: Gray\"> --&gt;</span>&lt;/author&gt;\r\n &lt;<a title=\"The textual component of the alert to display to the user.\" class=\"dict\" href=\"alert-definitions.html#Alert.note\"><b>note</b></a> value=&quot;[<span style=\"color: darkgreen\"><a href=\"datatypes.html#string\">string</a></span>]&quot;/&gt;<span style=\"color: Gray\">&lt;!--</span> <span style=\"color: brown\"><b>1..1</b></span> <span style=\"color: navy\">Text of alert</span><span style=\"color: Gray\"> --&gt;</span>\r\n&lt;/Alert&gt;\r\n</pre></div>";

View File

@ -3,10 +3,12 @@ package ca.uhn.fhir.model;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import org.hl7.fhir.dstu3.model.ExplanationOfBenefit; import org.hl7.fhir.dstu3.model.ExplanationOfBenefit;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Test; import org.junit.Test;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.primitive.XhtmlDt;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
public class XhtmlNodeTest { public class XhtmlNodeTest {
@ -20,6 +22,15 @@ public class XhtmlNodeTest {
private static FhirContext ourCtx = FhirContext.forDstu3(); private static FhirContext ourCtx = FhirContext.forDstu3();
@Test
public void testParseRsquo() {
XhtmlNode dt = new XhtmlNode();
dt.setValueAsString("It&rsquo;s January again");
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">Its January again</div>", dt.getValueAsString());
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">Its January again</div>", new XhtmlNode().setValue(dt.getValue()).getValueAsString());
}
/** /**
* See #443 * See #443
*/ */

View File

@ -237,6 +237,10 @@
Declared extensions with multiple type() options listed in the @Child Declared extensions with multiple type() options listed in the @Child
annotation caused a crash on startup. Now this is supported. annotation caused a crash on startup. Now this is supported.
</action> </action>
<action type="add">
STU3 XHTML parser for narrative choked if the narrative contained
an <![CDATA[<code>&amp;rsquot;</code>]]> entity string.
</action>
</release> </release>
<release version="2.1" date="2016-11-11"> <release version="2.1" date="2016-11-11">
<action type="add"> <action type="add">