changeset 3203:810772486249

URI "/instances/.../file" can return DICOMweb JSON or XML, depending on Accept header
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 06 Feb 2019 15:45:16 +0100
parents ef4d86d05503
children 8792867b739a
files Core/DicomParsing/DicomWebJsonVisitor.cpp Core/DicomParsing/DicomWebJsonVisitor.h Core/Enumerations.cpp Core/Enumerations.h Core/Toolbox.cpp Core/Toolbox.h NEWS OrthancServer/OrthancRestApi/OrthancRestResources.cpp UnitTestsSources/DicomMapTests.cpp UnitTestsSources/UnitTestsMain.cpp
diffstat 10 files changed, 89 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomParsing/DicomWebJsonVisitor.cpp	Wed Feb 06 15:21:32 2019 +0100
+++ b/Core/DicomParsing/DicomWebJsonVisitor.cpp	Wed Feb 06 15:45:16 2019 +0100
@@ -306,9 +306,11 @@
 
 
 #if ORTHANC_ENABLE_PUGIXML == 1
-  void DicomWebJsonVisitor::FormatXml(pugi::xml_document& target) const
+  void DicomWebJsonVisitor::FormatXml(std::string& target) const
   {
-    DicomWebJsonToXml(target, result_);
+    pugi::xml_document doc;
+    DicomWebJsonToXml(doc, result_);
+    Toolbox::XmlToString(target, doc);
   }
 #endif
 
--- a/Core/DicomParsing/DicomWebJsonVisitor.h	Wed Feb 06 15:21:32 2019 +0100
+++ b/Core/DicomParsing/DicomWebJsonVisitor.h	Wed Feb 06 15:45:16 2019 +0100
@@ -37,10 +37,6 @@
 #  error Macro ORTHANC_ENABLE_PUGIXML must be defined to use this file
 #endif
 
-#if ORTHANC_ENABLE_PUGIXML == 1
-#  include <pugixml.hpp>
-#endif
-
 #include "ITagVisitor.h"
 
 #include <json/value.h>
@@ -109,7 +105,7 @@
     }
 
 #if ORTHANC_ENABLE_PUGIXML == 1
-    void FormatXml(pugi::xml_document& target) const;
+    void FormatXml(std::string& target) const;
 #endif
 
     virtual void VisitNotSupported(const std::vector<DicomTag>& parentTags,
--- a/Core/Enumerations.cpp	Wed Feb 06 15:21:32 2019 +0100
+++ b/Core/Enumerations.cpp	Wed Feb 06 15:45:16 2019 +0100
@@ -59,6 +59,8 @@
   static const char* const MIME_WOFF = "application/x-font-woff";
   static const char* const MIME_XML_2 = "text/xml";
   static const char* const MIME_ZIP = "application/zip";
+  static const char* const MIME_DICOM_WEB_JSON = "application/dicom+json";
+  static const char* const MIME_DICOM_WEB_XML = "application/dicom+xml";
 
   // This function is autogenerated by the script
   // "Resources/GenerateErrorCodes.py"
@@ -1107,6 +1109,12 @@
       case MimeType_PrometheusText:
         // https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format
         return "text/plain; version=0.0.4";
+
+      case MimeType_DicomWebJson:
+        return MIME_DICOM_WEB_JSON;
+                
+      case MimeType_DicomWebXml:
+        return MIME_DICOM_WEB_XML;
                 
       default:
         throw OrthancException(ErrorCode_ParameterOutOfRange);
@@ -1716,6 +1724,14 @@
     {
       return MimeType_Woff;
     }
+    else if (mime == MIME_DICOM_WEB_JSON)
+    {
+      return MimeType_DicomWebJson;
+    }
+    else if (mime == MIME_DICOM_WEB_XML)
+    {
+      return MimeType_DicomWebXml;
+    }
     else
     {
       throw OrthancException(ErrorCode_ParameterOutOfRange);
--- a/Core/Enumerations.h	Wed Feb 06 15:21:32 2019 +0100
+++ b/Core/Enumerations.h	Wed Feb 06 15:45:16 2019 +0100
@@ -104,9 +104,11 @@
     MimeType_Svg,
     MimeType_WebAssembly,
     MimeType_Xml,
-    MimeType_Woff,           // Web Open Font Format
+    MimeType_Woff,            // Web Open Font Format
     MimeType_Zip,
-    MimeType_PrometheusText  // Prometheus text-based exposition format (for metrics)
+    MimeType_PrometheusText,  // Prometheus text-based exposition format (for metrics)
+    MimeType_DicomWebJson,
+    MimeType_DicomWebXml
   };
 
   
--- a/Core/Toolbox.cpp	Wed Feb 06 15:21:32 2019 +0100
+++ b/Core/Toolbox.cpp	Wed Feb 06 15:45:16 2019 +0100
@@ -99,7 +99,6 @@
 
 #if ORTHANC_ENABLE_PUGIXML == 1
 #  include "ChunkedBuffer.h"
-#  include <pugixml.hpp>
 #endif
 
 
@@ -1023,11 +1022,16 @@
     decl.append_attribute("version").set_value("1.0");
     decl.append_attribute("encoding").set_value("utf-8");
 
+    XmlToString(target, doc);
+  }
+
+  void Toolbox::XmlToString(std::string& target,
+                            const pugi::xml_document& source)
+  {
     ChunkedBufferWriter writer;
-    doc.save(writer, "  ", pugi::format_default, pugi::encoding_utf8);
+    source.save(writer, "  ", pugi::format_default, pugi::encoding_utf8);
     writer.Flatten(target);
   }
-
 #endif
 
 
--- a/Core/Toolbox.h	Wed Feb 06 15:21:32 2019 +0100
+++ b/Core/Toolbox.h	Wed Feb 06 15:45:16 2019 +0100
@@ -68,6 +68,10 @@
  **/
 
 
+#if ORTHANC_ENABLE_PUGIXML == 1
+#  include <pugixml.hpp>
+#endif
+
 
 namespace Orthanc
 {
@@ -192,6 +196,11 @@
                    const std::string& arrayElement = "item");
 #endif
 
+#if ORTHANC_ENABLE_PUGIXML == 1
+    void XmlToString(std::string& target,
+                     const pugi::xml_document& source);
+#endif
+
     bool IsInteger(const std::string& str);
 
     void CopyJsonWithoutComments(Json::Value& target,
--- a/NEWS	Wed Feb 06 15:21:32 2019 +0100
+++ b/NEWS	Wed Feb 06 15:45:16 2019 +0100
@@ -13,6 +13,8 @@
 --------
 
 * API version has been upgraded to 1.4
+* URI "/instances/.../file" can return DICOMweb JSON or XML, depending
+  on the content of the "Accept" HTTP header
 * New URI "/tools/metrics" to dynamically enable/disable the collection of metrics
 * New URI "/tools/metrics-prometheus" to retrieve metrics using Prometheus text format
 * URI "/peers?expand" provides more information about the peers
--- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp	Wed Feb 06 15:21:32 2019 +0100
+++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp	Wed Feb 06 15:45:16 2019 +0100
@@ -35,6 +35,7 @@
 #include "OrthancRestApi.h"
 
 #include "../../Core/Compression/GzipCompressor.h"
+#include "../../Core/DicomParsing/DicomWebJsonVisitor.h"
 #include "../../Core/DicomParsing/FromDcmtkBridge.h"
 #include "../../Core/DicomParsing/Internals/DicomImageDecoder.h"
 #include "../../Core/HttpServer/HttpContentNegociation.h"
@@ -244,6 +245,45 @@
     ServerContext& context = OrthancRestApi::GetContext(call);
 
     std::string publicId = call.GetUriComponent("id", "");
+
+    IHttpHandler::Arguments::const_iterator accept = call.GetHttpHeaders().find("accept");
+    if (accept != call.GetHttpHeaders().end())
+    {
+      // New in Orthanc 1.5.4
+      try
+      {
+        MimeType mime = StringToMimeType(accept->second.c_str());
+
+        if (mime == MimeType_DicomWebJson ||
+            mime == MimeType_DicomWebXml)
+        {
+          DicomWebJsonVisitor visitor;
+          
+          {
+            ServerContext::DicomCacheLocker locker(OrthancRestApi::GetContext(call), publicId);
+            locker.GetDicom().Apply(visitor);
+          }
+
+          if (mime == MimeType_DicomWebJson)
+          {
+            std::string s = visitor.GetResult().toStyledString();
+            call.GetOutput().AnswerBuffer(s, MimeType_DicomWebJson);
+          }
+          else
+          {
+            std::string xml;
+            visitor.FormatXml(xml);
+            call.GetOutput().AnswerBuffer(xml, MimeType_DicomWebXml);
+          }
+          
+          return;
+        }
+      }
+      catch (OrthancException&)
+      {
+      }
+    }
+
     context.AnswerAttachment(call.GetOutput(), publicId, FileContentType_Dicom);
   }
 
--- a/UnitTestsSources/DicomMapTests.cpp	Wed Feb 06 15:21:32 2019 +0100
+++ b/UnitTestsSources/DicomMapTests.cpp	Wed Feb 06 15:45:16 2019 +0100
@@ -586,7 +586,7 @@
     ASSERT_EQ(1u, tag.getMemberNames().size());
   }
 
-  pugi::xml_document xml;
+  std::string xml;
   visitor.FormatXml(xml);
 }
 
@@ -616,7 +616,7 @@
     ASSERT_FLOAT_EQ(2.5f, value[3].asFloat());
   }
 
-  pugi::xml_document xml;
+  std::string xml;
   visitor.FormatXml(xml);
 }
 
@@ -758,7 +758,7 @@
   ASSERT_EQ("UT", visitor.GetResult() ["00400031"]["Value"][0].asString());
 
 
-  pugi::xml_document xml;
+  std::string xml;
   visitor.FormatXml(xml);
 }
 
@@ -802,6 +802,6 @@
   ASSERT_TRUE(items.find("item1") != items.end());
   ASSERT_TRUE(items.find("item2") != items.end());
 
-  pugi::xml_document xml;
+  std::string xml;
   visitor.FormatXml(xml);
 }
--- a/UnitTestsSources/UnitTestsMain.cpp	Wed Feb 06 15:21:32 2019 +0100
+++ b/UnitTestsSources/UnitTestsMain.cpp	Wed Feb 06 15:45:16 2019 +0100
@@ -756,6 +756,8 @@
   ASSERT_EQ(MimeType_Xml, StringToMimeType("application/xml"));
   ASSERT_EQ(MimeType_Xml, StringToMimeType("text/xml"));
   ASSERT_EQ(MimeType_Xml, StringToMimeType(EnumerationToString(MimeType_Xml)));
+  ASSERT_EQ(MimeType_DicomWebJson, StringToMimeType(EnumerationToString(MimeType_DicomWebJson)));
+  ASSERT_EQ(MimeType_DicomWebXml, StringToMimeType(EnumerationToString(MimeType_DicomWebXml)));
   ASSERT_THROW(StringToMimeType("nope"), OrthancException);
 
   ASSERT_TRUE(IsResourceLevelAboveOrEqual(ResourceType_Patient, ResourceType_Patient));