Doc updates

This commit is contained in:
jamesagnew 2014-04-02 08:05:16 -04:00
parent 81b2b1cc50
commit f7a4b48e07
13 changed files with 205 additions and 61 deletions

View File

@ -264,8 +264,10 @@
var pres = elements[i].getElementsByTagName("pre"); var pres = elements[i].getElementsByTagName("pre");
for (var j = 0; j < pres.length; j++) { for (var j = 0; j < pres.length; j++) {
var pre = pres[j]; var pre = pres[j];
if (pre.innerHTML.match(/\\\*/)) { if (pre.innerHTML.match(/\/\*/)) {
pre.className = 'brush: java'; pre.className = 'brush: java';
} else if (pre.innerHTML.match(/^\#/)) {
pre.className = 'brush: bash';
} else if (pre.innerHTML.match(/\&lt\;\//)) { } else if (pre.innerHTML.match(/\&lt\;\//)) {
pre.className = 'brush: xml'; pre.className = 'brush: xml';
} else { } else {

View File

@ -51,9 +51,14 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
private HashMap<String, String> myProfileToNarrativeName; private HashMap<String, String> myProfileToNarrativeName;
private HashMap<Class<?>, String> myClassToNarrativeName; private HashMap<Class<?>, String> myClassToNarrativeName;
private HashMap<String, String> myNameToNarrativeTemplate; private HashMap<String, String> myNameToNarrativeTemplate;
private boolean myApplyDefaultDatatypeTemplates=true;
private volatile boolean myInitialized; private volatile boolean myInitialized;
@Override
public NarrativeDt generateNarrative(IResource theResource) {
return generateNarrative(null, theResource);
}
@Override @Override
public NarrativeDt generateNarrative(String theProfile, IResource theResource) { public NarrativeDt generateNarrative(String theProfile, IResource theResource) {
if (!myInitialized) { if (!myInitialized) {
@ -115,6 +120,9 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
} }
try { try {
if (myApplyDefaultDatatypeTemplates) {
loadProperties(DefaultThymeleafNarrativeGenerator.NARRATIVES_PROPERTIES);
}
loadProperties(propFileName); loadProperties(propFileName);
} catch (IOException e) { } catch (IOException e) {
throw new ConfigurationException("Can not load property file " + propFileName, e); throw new ConfigurationException("Can not load property file " + propFileName, e);
@ -139,9 +147,12 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
protected abstract String getPropertyFile(); protected abstract String getPropertyFile();
/** /**
* If set to <code>true</code> (which is the default), most whitespace will be trimmed from the generated narrative before it is returned. * If set to <code>true</code> (which is the default), most whitespace will
* be trimmed from the generated narrative before it is returned.
* <p> * <p>
* Note that in order to preserve formatting, not all whitespace is trimmed. Repeated whitespace characters (e.g. "\n \n ") will be trimmed to a single space. * Note that in order to preserve formatting, not all whitespace is trimmed.
* Repeated whitespace characters (e.g. "\n \n ") will be
* trimmed to a single space.
* </p> * </p>
*/ */
public boolean isCleanWhitespace() { public boolean isCleanWhitespace() {
@ -149,24 +160,30 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
} }
/** /**
* If set to <code>true</code>, which is the default, if any failure occurs during narrative generation the generator will suppress any generated exceptions, and simply return a default narrative * If set to <code>true</code>, which is the default, if any failure occurs
* indicating that no narrative is available. * during narrative generation the generator will suppress any generated
* exceptions, and simply return a default narrative indicating that no
* narrative is available.
*/ */
public boolean isIgnoreFailures() { public boolean isIgnoreFailures() {
return myIgnoreFailures; return myIgnoreFailures;
} }
/** /**
* If set to true, will return an empty narrative block for any profiles where no template is available * If set to true, will return an empty narrative block for any profiles
* where no template is available
*/ */
public boolean isIgnoreMissingTemplates() { public boolean isIgnoreMissingTemplates() {
return myIgnoreMissingTemplates; return myIgnoreMissingTemplates;
} }
/** /**
* If set to <code>true</code> (which is the default), most whitespace will be trimmed from the generated narrative before it is returned. * If set to <code>true</code> (which is the default), most whitespace will
* be trimmed from the generated narrative before it is returned.
* <p> * <p>
* Note that in order to preserve formatting, not all whitespace is trimmed. Repeated whitespace characters (e.g. "\n \n ") will be trimmed to a single space. * Note that in order to preserve formatting, not all whitespace is trimmed.
* Repeated whitespace characters (e.g. "\n \n ") will be
* trimmed to a single space.
* </p> * </p>
*/ */
public void setCleanWhitespace(boolean theCleanWhitespace) { public void setCleanWhitespace(boolean theCleanWhitespace) {
@ -174,15 +191,18 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
} }
/** /**
* If set to <code>true</code>, which is the default, if any failure occurs during narrative generation the generator will suppress any generated exceptions, and simply return a default narrative * If set to <code>true</code>, which is the default, if any failure occurs
* indicating that no narrative is available. * during narrative generation the generator will suppress any generated
* exceptions, and simply return a default narrative indicating that no
* narrative is available.
*/ */
public void setIgnoreFailures(boolean theIgnoreFailures) { public void setIgnoreFailures(boolean theIgnoreFailures) {
myIgnoreFailures = theIgnoreFailures; myIgnoreFailures = theIgnoreFailures;
} }
/** /**
* If set to true, will return an empty narrative block for any profiles where no template is available * If set to true, will return an empty narrative block for any profiles
* where no template is available
*/ */
public void setIgnoreMissingTemplates(boolean theIgnoreMissingTemplates) { public void setIgnoreMissingTemplates(boolean theIgnoreMissingTemplates) {
myIgnoreMissingTemplates = theIgnoreMissingTemplates; myIgnoreMissingTemplates = theIgnoreMissingTemplates;
@ -261,11 +281,11 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
} else if (name.startsWith("file:")) { } else if (name.startsWith("file:")) {
File file = new File(name.substring("file:".length())); File file = new File(name.substring("file:".length()));
if (file.exists() == false) { if (file.exists() == false) {
throw new IOException("Can not read file: " + file.getAbsolutePath()); throw new IOException("File not found: " + file.getAbsolutePath());
} }
return new FileInputStream(file); return new FileInputStream(file);
} else { } else {
throw new IOException("Invalid resource name: '" + name + "'"); throw new IOException("Invalid resource name: '" + name + "' (must start with classpath: or file: )");
} }
} }
@ -337,11 +357,14 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
final IStandardExpression expression = expressionParser.parseExpression(configuration, theArguments, attributeValue); final IStandardExpression expression = expressionParser.parseExpression(configuration, theArguments, attributeValue);
final Object value = expression.execute(configuration, theArguments); final Object value = expression.execute(configuration, theArguments);
theElement.removeAttribute(theAttributeName);
theElement.clearChildren();
Context context = new Context(); Context context = new Context();
context.setVariable("resource", value); context.setVariable("resource", value);
String name = myClassToNarrativeName.get(value.getClass()); String name = myClassToNarrativeName.get(value.getClass());
if (name == null) { if (name == null) {
if (myIgnoreMissingTemplates) { if (myIgnoreMissingTemplates) {
ourLog.debug("No narrative template available for type: {}", value.getClass()); ourLog.debug("No narrative template available for type: {}", value.getClass());
@ -354,9 +377,6 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
String result = myProfileTemplateEngine.process(name, context); String result = myProfileTemplateEngine.process(name, context);
Document dom = DOMUtils.getXhtmlDOMFor(new StringReader(result)); Document dom = DOMUtils.getXhtmlDOMFor(new StringReader(result));
theElement.removeAttribute(theAttributeName);
theElement.clearChildren();
Element firstChild = (Element) dom.getFirstChild(); Element firstChild = (Element) dom.getFirstChild();
for (Node next : firstChild.getChildren()) { for (Node next : firstChild.getChildren()) {
theElement.addChild(next); theElement.addChild(next);

View File

@ -1,16 +1,13 @@
package ca.uhn.fhir.narrative; package ca.uhn.fhir.narrative;
import java.io.IOException;
public class DefaultThymeleafNarrativeGenerator extends BaseThymeleafNarrativeGenerator implements INarrativeGenerator { public class DefaultThymeleafNarrativeGenerator extends BaseThymeleafNarrativeGenerator implements INarrativeGenerator {
public DefaultThymeleafNarrativeGenerator() throws IOException { static final String NARRATIVES_PROPERTIES = "classpath:ca/uhn/fhir/narrative/narratives.properties";
super();
}
@Override @Override
protected String getPropertyFile() { protected String getPropertyFile() {
return "classpath:ca/uhn/fhir/narrative/narratives.properties"; return NARRATIVES_PROPERTIES;
} }
} }

View File

@ -6,6 +6,8 @@ import ca.uhn.fhir.parser.DataFormatException;
public interface INarrativeGenerator { public interface INarrativeGenerator {
public NarrativeDt generateNarrative(String theProfile, IResource theResource) throws DataFormatException; NarrativeDt generateNarrative(String theProfile, IResource theResource) throws DataFormatException;
NarrativeDt generateNarrative(IResource theResource);
} }

View File

@ -0,0 +1,25 @@
package example;
import java.io.IOException;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.narrative.CustomThymeleafNarrativeGenerator;
public class NarrativeGenerator {
@Test
public void testGenerator() throws IOException {
//START SNIPPET: gen
String propFile = "classpath:/com/foo/customnarrative.properties";
CustomThymeleafNarrativeGenerator gen = new CustomThymeleafNarrativeGenerator(propFile);
FhirContext ctx = new FhirContext();
ctx.setNarrativeGenerator(gen);
//END SNIPPET: gen
}
}

View File

@ -56,6 +56,7 @@
<script type="text/javascript" src="syntaxhighlighter/shCore.js"></script> <script type="text/javascript" src="syntaxhighlighter/shCore.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushJScript.js"></script> <script type="text/javascript" src="syntaxhighlighter/shBrushJScript.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushJava.js"></script> <script type="text/javascript" src="syntaxhighlighter/shBrushJava.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushBash.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushXml.js"></script> <script type="text/javascript" src="syntaxhighlighter/shBrushXml.js"></script>
<link href="syntaxhighlighter/shCore.css" rel="stylesheet" type="text/css" /> <link href="syntaxhighlighter/shCore.css" rel="stylesheet" type="text/css" />
<link href="syntaxhighlighter/shThemeDefault.css" rel="stylesheet" type="text/css" /> <link href="syntaxhighlighter/shThemeDefault.css" rel="stylesheet" type="text/css" />

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<document xmlns="http://maven.apache.org/XDOC/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
<properties>
<title>Download - HAPI FHIR</title>
<author email="jamesagnew@users.sourceforge.net">James Agnew</author>
</properties>
<body>
<section name="Downloading HAPI FHIR">
<p>
The easiest way to get started with HAPI-FHIR is to either download the
source code from our
<a href="https://sourceforge.net/p/hl7api/fhircode/ci/master/tree/">Git Repository</a>
, or to use Maven:
</p>
<source><![CDATA[<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>${project.version}</version>
</dependency>]]></source>
<subsection name="Non-Maven Users">
<p>
Non-maven users can grab the files from the
<a href="https://sourceforge.net/projects/hl7api/files/hapi-fhir/">Sourceforge File Release System</a>.
</p>
</subsection>
</section>
</body>
</document>

View File

@ -9,7 +9,7 @@
<body> <body>
<!-- The body of the document contains a number of sections --> <!-- The body of the document contains a number of sections -->
<section name="Developing using FHIR-HAPI"> <section name="Developing using HAPI FHIR">
<macro name="toc"> <macro name="toc">
</macro> </macro>
@ -45,23 +45,9 @@
<section name="Getting Started"> <section name="Getting Started">
<p> <p>
The easiest way to get started with HAPI-FHIR is to either download the To get started with HAPI FHIR, first download a copy and add it
source code from our to your project. See the <a href="doc_download.html">Download Page</a>
<a href="https://sourceforge.net/p/hl7api/fhircode/ci/master/tree/">Git Repository</a> for instructions.
, or to use Maven:
</p>
<source><![CDATA[<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>]]></source>
<p>
If you are not using Maven, you can download the latest version
of the snapshot JAR (and optionally the Javadoc and Sources JAR) from the Maven
repo here: <a href="http://oss.sonatype.org/content/repositories/snapshots/ca/uhn/hapi/fhir/hapi-fhir-base/1.0-SNAPSHOT/">download</a>.
Once a formal release has been created, it will be uploaded through the Sourceforge
file release system (as the HAPI v2 libraries are).
</p> </p>
<subsection name="Introcuding the FHIR Context"> <subsection name="Introcuding the FHIR Context">

View File

@ -111,6 +111,63 @@
</section> </section>
<section name="Creating your own Templates">
<p>
To use your own templates for narrative generation,
simply create one or more templates, using the Thymeleaf
HTML based syntax.
</p>
<macro name="snippet">
<param name="file" value="src/test/resources/narrative/Practitioner.html" />
</macro>
<p>
Then create a properties file which describes your
templates. In this properties file, each resource to
be defined has a pair or properties.
</p>
<p>
The first (name.class) defines the class name of the resource to define a
template for. The second (name.narrative) defines the path/classpath to the
template file. The format of this path is <code>file:/path/foo.html</code> or <code>classpath:/com/classpath/foo.html</code>
</p>
<source><![CDATA[# Two property lines in the file per template
practitioner.class=ca.uhn.fhir.model.dstu.resource.Practitioner
practitioner.narrative=file:src/test/resources/narrative/Practitioner.html
observation.class=ca.uhn.fhir.model.dstu.resource.Observation
observation.narrative=file:src/test/resources/narrative/Observation.html
# etc...]]></source>
<p>
You may also override/define behaviour for datatypes. These datatype narrative
definitions will be used as content within <code>th:narrative</code> blocks
in resource templates. See the example resource template above for an example.
</p>
<source><![CDATA[# datatypes use the same format as resources
humanname.class=ca.uhn.fhir.model.dstu.composite.HumanNameDt
humanname.narrative=classpath:ca/uhn/fhir/narrative/HumanNameDt.html]]></source>
<p>
Finally, use the
<a href="./apidocs/ca/uhn/fhir/narrative/CustomThymeleafNarrativeGenerator.html">CustomThymeleafNarrativeGenerator</a>
and provide it
to the FhirContext.
</p>
<macro name="snippet">
<param name="id" value="gen" />
<param name="file" value="src/site/example/java/example/NarrativeGenerator.java" />
</macro>
</section>
</body> </body>
</document> </document>

View File

@ -1,18 +1,36 @@
package ca.uhn.fhir.narrative; package ca.uhn.fhir.narrative;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.IOException; import java.io.IOException;
import org.junit.Test; import org.junit.Test;
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
import ca.uhn.fhir.model.dstu.resource.Practitioner;
public class CustomThymeleafNarrativeGeneratorTest { public class CustomThymeleafNarrativeGeneratorTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CustomThymeleafNarrativeGeneratorTest.class);
@Test @Test
public void testGenerator() throws IOException { public void testGenerator() throws IOException {
CustomThymeleafNarrativeGenerator gen = new CustomThymeleafNarrativeGenerator("src/test/resources/narrative/customnarrative.properties"); CustomThymeleafNarrativeGenerator gen = new CustomThymeleafNarrativeGenerator("file:src/test/resources/narrative/customnarrative.properties");
Practitioner p = new Practitioner();
p.addIdentifier("sys", "val1");
p.addIdentifier("sys", "val2");
p.getAddress().addLine("line1").addLine("line2");
p.getName().addFamily("fam1").addGiven("given");
NarrativeDt narrative = gen.generateNarrative(p);
String actual = narrative.getDiv().getValueAsString();
ourLog.info(actual);
assertThat(actual, containsString("<h1>Name</h1><div> given <b>FAM1 </b></div><h1>Address</h1><div><span>line1 </span><br/><span>line2 </span><br/></div></div>"));
} }
} }

View File

@ -27,7 +27,7 @@ public class DefaultThymeleafNarrativeGeneratorTest {
private DefaultThymeleafNarrativeGenerator gen; private DefaultThymeleafNarrativeGenerator gen;
@Before @Before
public void before() throws IOException { public void before() {
gen = new DefaultThymeleafNarrativeGenerator(); gen = new DefaultThymeleafNarrativeGenerator();
gen.setIgnoreFailures(false); gen.setIgnoreFailures(false);
gen.setIgnoreMissingTemplates(false); gen.setIgnoreMissingTemplates(false);

View File

@ -10,12 +10,10 @@
HAPI also defines a custom tag, th:narrative="value", which is HAPI also defines a custom tag, th:narrative="value", which is
used to render a datatype. used to render a datatype.
--> -->
<div th:narrative="${resource.addressFirstRep}"></div> <h1>Name</h1>
<div th:narrative="${resource.name}"></div>
<h1>Address</h1>
<div th:narrative="${resource.address}"></div>
<!--
HAPI also defines a custom tag, th:narrative="value", which is
used to render a datatype.
-->
<div th:narrative="${resource.nameFirstRep}"></div>
</div> </div>

View File

@ -9,7 +9,7 @@
# Format is file:/path/foo.html or classpath:/com/classpath/foo.html # Format is file:/path/foo.html or classpath:/com/classpath/foo.html
# #
practitioner.class=ca.uhn.fhir.model.dstu.resource.Practitioner practitioner.class=ca.uhn.fhir.model.dstu.resource.Practitioner
practitioner.narrative=file:src/test/resource/narrative/Practitioner.html practitioner.narrative=file:src/test/resources/narrative/Practitioner.html
# You may also override/define behaviour for datatypes # You may also override/define behaviour for datatypes
humanname.class=ca.uhn.fhir.model.dstu.composite.HumanNameDt humanname.class=ca.uhn.fhir.model.dstu.composite.HumanNameDt