From cd8c970045e7694c346c098998a8de652d217649 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 1 Dec 2022 16:56:55 +1100 Subject: [PATCH 01/10] Add logging to package client --- .../main/java/org/hl7/fhir/utilities/npm/PackageClient.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java index f1a854739..9b48f3d1e 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java @@ -75,10 +75,11 @@ public class PackageClient { } public List getVersions(String id) throws IOException { + String url = Utilities.pathURL(address, id); List res = new ArrayList<>(); JsonObject json; try { - json = fetchJson(Utilities.pathURL(address, id)); + json = fetchJson(url); JsonObject versions = json.getJsonObject("versions"); boolean hasDates = true; if (versions != null) { @@ -103,6 +104,7 @@ public class PackageClient { Collections.sort(res, new PackageInfo.PackageInfoSorter(false)); } } catch (Exception e) { + System.out.println("Error fetching "+url+": "+e.getMessage()); } return res; } From 21102fa8d76ae9a78b1ae0b6e51d97a21dfc6c26 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 5 Dec 2022 13:38:17 +1100 Subject: [PATCH 02/10] fix version converter for code systems --- .../loaders/loaderR5/R2016MayToR5Loader.java | 6 ++++++ .../convertors/loaders/loaderR5/R2ToR5Loader.java | 14 +++++++++++--- .../convertors/loaders/loaderR5/R3ToR5Loader.java | 6 ++++++ .../convertors/loaders/loaderR5/R4BToR5Loader.java | 7 +++++++ .../convertors/loaders/loaderR5/R4ToR5Loader.java | 7 +++++++ .../convertors/loaders/loaderR5/R5ToR5Loader.java | 7 +++++++ 6 files changed, 44 insertions(+), 3 deletions(-) diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R2016MayToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R2016MayToR5Loader.java index 89903a31c..9fe86f8ee 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R2016MayToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R2016MayToR5Loader.java @@ -151,4 +151,10 @@ public class R2016MayToR5Loader extends BaseLoaderR5 { } } } + + @Override + public List getCodeSystems() { + return new ArrayList<>(); + } + } \ No newline at end of file diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R2ToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R2ToR5Loader.java index 303ccad8d..de1bfa1bd 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R2ToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R2ToR5Loader.java @@ -122,9 +122,6 @@ public class R2ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader r2 = new XmlParser().parse(stream); org.hl7.fhir.r5.model.Resource r5 = VersionConvertorFactory_10_50.convertResource(r2, advisor); setPath(r5); - if (!advisor.getCslist().isEmpty()) { - throw new FHIRException("Error: Cannot have included code systems"); - } if (killPrimitives) { throw new FHIRException("Cannot kill primitives when using deferred loading"); } @@ -152,4 +149,15 @@ public class R2ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader } } } + + @Override + public List getCodeSystems() { + List list = new ArrayList<>(); + if (!advisor.getCslist().isEmpty()) { + list.addAll(advisor.getCslist()); + advisor.getCslist().clear(); + } + return list; + } + } \ No newline at end of file diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R3ToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R3ToR5Loader.java index 85a5eed3d..58723f2ac 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R3ToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R3ToR5Loader.java @@ -153,4 +153,10 @@ public class R3ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader } } } + + @Override + public List getCodeSystems() { + return new ArrayList<>(); + } + } \ No newline at end of file diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R4BToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R4BToR5Loader.java index 233c2b276..d9007082b 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R4BToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R4BToR5Loader.java @@ -160,4 +160,11 @@ public class R4BToR5Loader extends BaseLoaderR5 implements IContextResourceLoade } } } + + @Override + public List getCodeSystems() { + return new ArrayList<>(); + } + + } \ No newline at end of file diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R4ToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R4ToR5Loader.java index c5a62942b..310a9d218 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R4ToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R4ToR5Loader.java @@ -160,4 +160,11 @@ public class R4ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader } } } + + @Override + public List getCodeSystems() { + return new ArrayList<>(); + } + + } \ No newline at end of file diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R5ToR5Loader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R5ToR5Loader.java index 9518ab1c3..d9161c27e 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R5ToR5Loader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/loaderR5/R5ToR5Loader.java @@ -151,4 +151,11 @@ public class R5ToR5Loader extends BaseLoaderR5 { } } } + + @Override + public List getCodeSystems() { + return new ArrayList<>(); + } + + } \ No newline at end of file From 9c0732158b51c1c08897e03c4c906e4486b933cb Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 5 Dec 2022 13:40:03 +1100 Subject: [PATCH 03/10] fully convert package version --- .../misc/NpmPackageVersionConverter.java | 55 ++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java index 6c19fea01..251e7461b 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/NpmPackageVersionConverter.java @@ -27,6 +27,10 @@ import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_50; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_40; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50; +import org.hl7.fhir.r5.model.Enumeration; +import org.hl7.fhir.r5.model.Enumerations.FHIRVersionEnumFactory; +import org.hl7.fhir.r5.model.ImplementationGuide; +import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.json.model.JsonArray; @@ -99,9 +103,10 @@ public class NpmPackageVersionConverter { Map output = new HashMap<>(); output.put("package/package.json", convertPackage(content.get("package/package.json"))); + output.put("package/other/spec.internals", convertSpec(content.get("package/other/spec.internals"))); for (Entry e : content.entrySet()) { - if (!e.getKey().equals("package/package.json")) { + if (!e.getKey().equals("package/package.json") && !e.getKey().equals("package/other/spec.internals")) { byte[] cnv = e.getValue(); try { JsonObject json = JsonParser.parseObject(e.getValue()); @@ -189,10 +194,17 @@ public class NpmPackageVersionConverter { return JsonParser.composeBytes(json); } + private byte[] convertSpec(byte[] cnt) throws IOException { + JsonObject json = JsonParser.parseObject(cnt); + json.set("ig-version", version); + return JsonParser.composeBytes(json, true); + } + private byte[] convertResource(String n, byte[] cnt) { try { if (VersionUtilities.isR2Ver(currentVersion)) { org.hl7.fhir.dstu2.model.Resource res = new org.hl7.fhir.dstu2.formats.JsonParser().parse(cnt); + convertResourceR2(res); if (VersionUtilities.isR2Ver(version)) { return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(res); } else if (VersionUtilities.isR2BVer(version)) { @@ -206,6 +218,7 @@ public class NpmPackageVersionConverter { } } else if (VersionUtilities.isR2BVer(currentVersion)) { org.hl7.fhir.dstu2016may.model.Resource res = new org.hl7.fhir.dstu2016may.formats.JsonParser().parse(cnt); + convertResourceR2B(res); if (VersionUtilities.isR2Ver(version)) { return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(VersionConvertorFactory_10_30.convertResource(VersionConvertorFactory_14_30.convertResource(res))); } else if (VersionUtilities.isR2BVer(version)) { @@ -219,6 +232,7 @@ public class NpmPackageVersionConverter { } } else if (VersionUtilities.isR3Ver(currentVersion)) { org.hl7.fhir.dstu3.model.Resource res = new org.hl7.fhir.dstu3.formats.JsonParser().parse(cnt); + convertResourceR3(res); if (VersionUtilities.isR2Ver(version)) { return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(VersionConvertorFactory_10_30.convertResource(res)); } else if (VersionUtilities.isR2BVer(version)) { @@ -232,6 +246,7 @@ public class NpmPackageVersionConverter { } } else if (VersionUtilities.isR4Ver(currentVersion)) { org.hl7.fhir.r4.model.Resource res = new org.hl7.fhir.r4.formats.JsonParser().parse(cnt); + convertResourceR4(res); if (VersionUtilities.isR2Ver(version)) { return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(VersionConvertorFactory_10_40.convertResource(res, new PR2Handler())); } else if (VersionUtilities.isR2BVer(version)) { @@ -245,6 +260,7 @@ public class NpmPackageVersionConverter { } } else if (VersionUtilities.isR5Ver(currentVersion)) { org.hl7.fhir.r5.model.Resource res = new org.hl7.fhir.r5.formats.JsonParser().parse(cnt); + convertResourceR5(res); if (VersionUtilities.isR2Ver(version)) { return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(VersionConvertorFactory_10_50.convertResource(res)); } else if (VersionUtilities.isR2BVer(version)) { @@ -265,4 +281,41 @@ public class NpmPackageVersionConverter { } } + private void convertResourceR2(org.hl7.fhir.dstu2.model.Resource res) { + if (res instanceof org.hl7.fhir.dstu2.model.ImplementationGuide) { + org.hl7.fhir.dstu2.model.ImplementationGuide ig = (org.hl7.fhir.dstu2.model.ImplementationGuide) res; + ig.setFhirVersion(version); + } + } + + private void convertResourceR2B(org.hl7.fhir.dstu2016may.model.Resource res) { + if (res instanceof org.hl7.fhir.dstu2016may.model.ImplementationGuide) { + org.hl7.fhir.dstu2016may.model.ImplementationGuide ig = (org.hl7.fhir.dstu2016may.model.ImplementationGuide) res; + ig.setFhirVersion(version); + } + } + + private void convertResourceR3(org.hl7.fhir.dstu3.model.Resource res) { + if (res instanceof org.hl7.fhir.dstu3.model.ImplementationGuide) { + org.hl7.fhir.dstu3.model.ImplementationGuide ig = (org.hl7.fhir.dstu3.model.ImplementationGuide) res; + ig.setFhirVersion(version); + } + } + + private void convertResourceR4(org.hl7.fhir.r4.model.Resource res) { + if (res instanceof org.hl7.fhir.r4.model.ImplementationGuide) { + org.hl7.fhir.r4.model.ImplementationGuide ig = (org.hl7.fhir.r4.model.ImplementationGuide) res; + ig.getFhirVersion().clear(); + ig.getFhirVersion().add(new org.hl7.fhir.r4.model.Enumeration<>(new org.hl7.fhir.r4.model.Enumerations.FHIRVersionEnumFactory(), version)); + } + } + + private void convertResourceR5(Resource res) { + if (res instanceof ImplementationGuide) { + ImplementationGuide ig = (ImplementationGuide) res; + ig.getFhirVersion().clear(); + ig.getFhirVersion().add(new Enumeration<>(new FHIRVersionEnumFactory(), version)); + } + } + } \ No newline at end of file From 54875fd17e73967f09d63b551cda9d5630b2ad95 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 5 Dec 2022 13:40:17 +1100 Subject: [PATCH 04/10] fix broken link to base spec --- .../main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java index b4f3c14c2..fb63b36f8 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java @@ -4497,7 +4497,7 @@ public class ProfileUtilities extends TranslatingUtilities { Piece p = gc.addText(ProfileUtilities.CONSTRAINT_CHAR); p.setHint(translate("sd.table", "This element has or is affected by constraints ("+listConstraintsAndConditions(element)+")")); p.addStyle(CONSTRAINT_STYLE); - p.setReference(VersionUtilities.getSpecUrl(context.getVersion())+"conformance-rules.html#constraints"); + p.setReference(Utilities.pathURL(VersionUtilities.getSpecUrl(context.getVersion()), "conformance-rules.html#constraints")); } if (element != null && element.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) { StandardsStatus ss = StandardsStatus.fromCode(element.getExtensionString(ToolingExtensions.EXT_STANDARDS_STATUS)); From cacf27428e6bb5c67914bc89b4e6cba2ea03dab0 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 5 Dec 2022 13:41:01 +1100 Subject: [PATCH 05/10] Fix rendering of Timing to not have specific verb --- .../java/org/hl7/fhir/r5/context/IWorkerContext.java | 9 ++++++++- .../main/java/org/hl7/fhir/r5/model/Enumerations.java | 4 ++++ .../java/org/hl7/fhir/r5/renderers/DataRenderer.java | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java index 0b34be2ac..7d1666440 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java @@ -310,7 +310,14 @@ public interface IWorkerContext { * @throws IOException * @throws JsonSyntaxException */ - IContextResourceLoader getNewLoader(NpmPackage npm) throws JsonSyntaxException, IOException; + IContextResourceLoader getNewLoader(NpmPackage npm) throws JsonSyntaxException, IOException; + + /** + * called when processing R2 for implicit code systems in ValueSets + * + * @return + */ + List getCodeSystems(); } /** diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Enumerations.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Enumerations.java index 399d32d35..64635d13f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Enumerations.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Enumerations.java @@ -11547,6 +11547,10 @@ The primary difference between a medicationusage and a medicationadministration return FHIRTypes.VISIONPRESCRIPTION; if ("Parameters".equals(codeString)) return FHIRTypes.PARAMETERS; + if ("Any".equals(codeString)) + return FHIRTypes.RESOURCE; + if ("CapabilityStatement2".equals(codeString)) + return FHIRTypes.CAPABILITYSTATEMENT; throw new IllegalArgumentException("Unknown FHIRTypes code '"+codeString+"'"); } public Enumeration fromType(Base code) throws FHIRException { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java index a284c1cf6..636bc80bd 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java @@ -1574,7 +1574,7 @@ public class DataRenderer extends Renderer { if (rep.hasOffset()) { st = Integer.toString(rep.getOffset())+"min "; } - b.append("Do "+st); + b.append(st); for (Enumeration wh : rep.getWhen()) b.append(displayEventCode(wh.getValue())); } else { @@ -1592,7 +1592,7 @@ public class DataRenderer extends Renderer { st = st + "-"+rep.getPeriodMax().toPlainString(); st = st + " "+displayTimeUnits(rep.getPeriodUnit()); } - b.append("Do "+st); + b.append(st); } if (rep.hasBoundsPeriod() && rep.getBoundsPeriod().hasEnd()) b.append("Until "+displayDateTime(rep.getBoundsPeriod().getEndElement())); From a0c28f33266aa3365fe3e336c3f9f8ea57fe7910 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 5 Dec 2022 13:41:31 +1100 Subject: [PATCH 06/10] Round trip XHTML faithfully wrt empty elements --- .../fhir/r5/test/utils/TestPackageLoader.java | 9 +++ .../fhir/utilities/xhtml/XhtmlComposer.java | 68 +++++++++++-------- .../hl7/fhir/utilities/xhtml/XhtmlNode.java | 24 +++++-- .../hl7/fhir/utilities/xhtml/XhtmlParser.java | 4 ++ .../fhir/utilities/tests/XhtmlNodeTest.java | 23 +++++++ 5 files changed, 92 insertions(+), 36 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestPackageLoader.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestPackageLoader.java index 130dce1db..448e4bb70 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestPackageLoader.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/TestPackageLoader.java @@ -2,12 +2,15 @@ package org.hl7.fhir.r5.test.utils; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r5.context.IWorkerContext.IContextResourceLoader; import org.hl7.fhir.r5.formats.JsonParser; import org.hl7.fhir.r5.formats.XmlParser; import org.hl7.fhir.r5.model.Bundle; +import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.utilities.npm.NpmPackage; @@ -43,4 +46,10 @@ public class TestPackageLoader implements IContextResourceLoader { public IContextResourceLoader getNewLoader(NpmPackage npm) { return this; } + + @Override + public List getCodeSystems() { + return new ArrayList<>(); + } + } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlComposer.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlComposer.java index 1ff09d550..53ae3b671 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlComposer.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlComposer.java @@ -90,40 +90,42 @@ public class XhtmlComposer { private void composeDoc(XhtmlDocument doc) throws IOException { // headers.... // dst.append("" + (pretty ? "\r\n" : "")); - for (XhtmlNode c : doc.getChildNodes()) + for (XhtmlNode c : doc.getChildNodes()) { writeNode(" ", c, false); + } // dst.append("" + (pretty ? "\r\n" : "")); } private void writeNode(String indent, XhtmlNode node, boolean noPrettyOverride) throws IOException { - if (node.getNodeType() == NodeType.Comment) + if (node.getNodeType() == NodeType.Comment) { writeComment(indent, node, noPrettyOverride); - else if (node.getNodeType() == NodeType.DocType) + } else if (node.getNodeType() == NodeType.DocType) { writeDocType(node); - else if (node.getNodeType() == NodeType.Instruction) + } else if (node.getNodeType() == NodeType.Instruction) { writeInstruction(node); - else if (node.getNodeType() == NodeType.Element) + } else if (node.getNodeType() == NodeType.Element) { writeElement(indent, node, noPrettyOverride); - else if (node.getNodeType() == NodeType.Document) + } else if (node.getNodeType() == NodeType.Document) { writeDocument(indent, node); - else if (node.getNodeType() == NodeType.Text) + } else if (node.getNodeType() == NodeType.Text) { writeText(node); - else if (node.getNodeType() == null) + } else if (node.getNodeType() == null) { throw new IOException("Null node type"); - else + } else { throw new IOException("Unknown node type: "+node.getNodeType().toString()); + } } private void writeText(XhtmlNode node) throws IOException { for (char c : node.getContent().toCharArray()) { - if (c == '&') + if (c == '&') { dst.append("&"); - else if (c == '<') + } else if (c == '<') { dst.append("<"); - else if (c == '>') + } else if (c == '>') { dst.append(">"); - else if (xml) { + } else if (xml) { if (c == '"') dst.append("""); else @@ -189,26 +191,34 @@ public class XhtmlComposer { indent = ""; // html self closing tags: http://xahlee.info/js/html5_non-closing_tag.html - if (node.getChildNodes().size() == 0 && (xml || Utilities.existsInList(node.getName(), "area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr"))) + boolean concise = node.getChildNodes().size() == 0; + if (node.hasEmptyExpanded() && node.getEmptyExpanded()) { + concise = false; + } + if (!xml && Utilities.existsInList(node.getName(), "area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr")) { + concise = false; + } + + if (concise) dst.append(indent + "<" + node.getName() + attributes(node) + "/>" + (pretty && !noPrettyOverride ? "\r\n" : "")); else { - boolean act = node.allChildrenAreText(); - if (act || !pretty || noPrettyOverride) - dst.append(indent + "<" + node.getName() + attributes(node)+">"); - else - dst.append(indent + "<" + node.getName() + attributes(node) + ">\r\n"); - if (node.getName() == "head" && node.getElement("meta") == null) - dst.append(indent + " " + (pretty && !noPrettyOverride ? "\r\n" : "")); + boolean act = node.allChildrenAreText(); + if (act || !pretty || noPrettyOverride) + dst.append(indent + "<" + node.getName() + attributes(node)+">"); + else + dst.append(indent + "<" + node.getName() + attributes(node) + ">\r\n"); + if (node.getName() == "head" && node.getElement("meta") == null) + dst.append(indent + " " + (pretty && !noPrettyOverride ? "\r\n" : "")); - for (XhtmlNode c : node.getChildNodes()) - writeNode(indent + " ", c, noPrettyOverride || node.isNoPretty()); - if (act) - dst.append("" + (pretty && !noPrettyOverride ? "\r\n" : "")); - else if (node.getChildNodes().get(node.getChildNodes().size() - 1).getNodeType() == NodeType.Text) - dst.append((pretty && !noPrettyOverride ? "\r\n"+ indent : "") + "" + (pretty && !noPrettyOverride ? "\r\n" : "")); - else - dst.append(indent + "" + (pretty && !noPrettyOverride ? "\r\n" : "")); + for (XhtmlNode c : node.getChildNodes()) + writeNode(indent + " ", c, noPrettyOverride || node.isNoPretty()); + if (act) + dst.append("" + (pretty && !noPrettyOverride ? "\r\n" : "")); + else if (node.getChildNodes().get(node.getChildNodes().size() - 1).getNodeType() == NodeType.Text) + dst.append((pretty && !noPrettyOverride ? "\r\n"+ indent : "") + "" + (pretty && !noPrettyOverride ? "\r\n" : "")); + else + dst.append(indent + "" + (pretty && !noPrettyOverride ? "\r\n" : "")); } } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java index fb7d8f11f..0869f1fb3 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java @@ -1,5 +1,7 @@ package org.hl7.fhir.utilities.xhtml; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + /* Copyright (c) 2011+, HL7, Inc. All rights reserved. @@ -38,21 +40,15 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.instance.model.api.IBaseXhtml; import org.hl7.fhir.utilities.MarkDownProcessor; -import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.MarkDownProcessor.Dialect; -import org.hl7.fhir.utilities.i18n.I18nConstants; -import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; +import org.hl7.fhir.utilities.Utilities; -import ca.uhn.fhir.model.api.annotation.ChildOrder; import ca.uhn.fhir.model.primitive.XhtmlDt; -import static org.apache.commons.lang3.StringUtils.isNotBlank; - @ca.uhn.fhir.model.api.annotation.DatatypeDef(name="xhtml") public class XhtmlNode implements IBaseXhtml { private static final long serialVersionUID = -4362547161441436492L; @@ -93,6 +89,7 @@ public class XhtmlNode implements IBaseXhtml { private boolean inPara; private boolean inLink; private boolean seperated; + private Boolean emptyExpanded; public XhtmlNode() { super(); @@ -416,6 +413,19 @@ public class XhtmlNode implements IBaseXhtml { } + public Boolean getEmptyExpanded() { + return emptyExpanded; + } + + public boolean hasEmptyExpanded() { + return emptyExpanded != null; + } + + public void setEmptyExpanded(Boolean emptyExpanded) { + this.emptyExpanded = emptyExpanded; + } + + @Override public String getValueAsString() { if (isEmpty()) { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlParser.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlParser.java index ea228c9b8..814754e8a 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlParser.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlParser.java @@ -506,10 +506,12 @@ public class XhtmlParser { if (peekChar() != '>') throw new FHIRFormatError("unexpected non-end of element "+n+" "+descLoc()); readChar(); + root.setEmptyExpanded(false); } else { unwindPoint = null; List p = new ArrayList<>(); parseElementInner(root, p, nsm, true); + root.setEmptyExpanded(true); } return result; } @@ -671,7 +673,9 @@ public class XhtmlParser { if (peekChar() != '>') throw new FHIRFormatError("unexpected non-end of element "+name+" "+descLoc()); readChar(); + node.setEmptyExpanded(false); } else { + node.setEmptyExpanded(true); parseElementInner(node, newParents, namespaceMap, "script".equals(name.getName())); } } diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/XhtmlNodeTest.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/XhtmlNodeTest.java index d585e2f9f..08c655edb 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/XhtmlNodeTest.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/tests/XhtmlNodeTest.java @@ -6,6 +6,8 @@ import java.io.ObjectOutputStream; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.utilities.TextFile; +import org.hl7.fhir.utilities.xhtml.XhtmlComposer; import org.hl7.fhir.utilities.xhtml.XhtmlNode; import org.hl7.fhir.utilities.xhtml.XhtmlParser; import org.junit.jupiter.api.Assertions; @@ -137,4 +139,25 @@ public class XhtmlNodeTest { Assertions.assertEquals("http://www.w3.org/1999/xlink", x.getChildNodes().get(0).getChildNodes().get(1).getAttributes().get("xmlns:xlink")); } + + @Test + public void testParseSvgElements() throws FHIRFormatError, IOException { + String src = BaseTestingUtilities.loadTestResource("xhtml", "xhtml-empty-elements.xml"); + XhtmlNode x = new XhtmlParser().parse(src, "xml"); + + + String xml = new XhtmlComposer(false, false).compose(x); + Assertions.assertEquals(src.trim(), xml.trim()); + } + + + @Test + public void testParseSvgF() throws FHIRFormatError, IOException { + String src = TextFile.fileToString("/Users/grahamegrieve/work/r5/source/fhir-exchanges.svg.html"); + XhtmlNode x = new XhtmlParser().parse(src, "svg"); + String xml = new XhtmlComposer(false, true).compose(x); + TextFile.stringToFile(xml, "/Users/grahamegrieve/work/r5/source/fhir-exchanges.svg.html"); + } + + } \ No newline at end of file From 037b615bfc421693aa4c9c02f7292330ecd5b3f3 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 5 Dec 2022 13:41:50 +1100 Subject: [PATCH 07/10] allow https://example... in questionnaires as example links --- .../fhir/validation/instance/type/QuestionnaireValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java index c70a3598f..091faa5dc 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/QuestionnaireValidator.java @@ -260,7 +260,7 @@ public class QuestionnaireValidator extends BaseValidator { if (questionnaireMode == QuestionnaireMode.REQUIRED) { qok = rule(errors, NO_RULE_DATE, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire); ok = qok && ok; - } else if (questionnaire.startsWith("http://example.org")) { + } else if (questionnaire.startsWith("http://example.org") || questionnaire.startsWith("https://example.org")) { qok = hint(errors, NO_RULE_DATE, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire); } else { qok = warning(errors, NO_RULE_DATE, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire); From 2891aae9b1cc2b013735014749318e0b2b3224b9 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 5 Dec 2022 13:42:03 +1100 Subject: [PATCH 08/10] fix test case dependency --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 10d03293d..3ccecaad9 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 5.4.0 - 1.1.128 + 1.1.129-SNAPSHOT 5.7.1 1.8.2 3.0.0-M5 From 5d29a88552deb0009008defe7381db6bc28b477c Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 5 Dec 2022 17:27:43 +1100 Subject: [PATCH 09/10] fix npe appending slashes --- .../src/main/java/org/hl7/fhir/utilities/Utilities.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java index 4e2485c1b..f27c4ff54 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java @@ -477,6 +477,9 @@ public class Utilities { } public static String appendForwardSlash(String definitions) { + if (definitions == null) { + return "/"; + } return definitions.endsWith("/") ? definitions : definitions + "/"; } From b778641cf6ba480a70a8e867ad906220422ea3b2 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 5 Dec 2022 17:27:52 +1100 Subject: [PATCH 10/10] fix bug in XHTML generation --- .../main/java/org/hl7/fhir/utilities/xhtml/XhtmlComposer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlComposer.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlComposer.java index 53ae3b671..221bf0af6 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlComposer.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlComposer.java @@ -196,7 +196,7 @@ public class XhtmlComposer { concise = false; } if (!xml && Utilities.existsInList(node.getName(), "area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr")) { - concise = false; + concise = true; } if (concise)