comparison Core/DicomParsing/DicomWebJsonVisitor.cpp @ 3221:4be505c2ac56

Separation of ideographic and phonetic characters in DICOMweb JSON and XML
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 14 Feb 2019 14:04:04 +0100
parents 810772486249
children b88937ef597b
comparison
equal deleted inserted replaced
3220:1a0b4db799e8 3221:4be505c2ac56
41 #include <boost/math/special_functions/round.hpp> 41 #include <boost/math/special_functions/round.hpp>
42 #include <boost/lexical_cast.hpp> 42 #include <boost/lexical_cast.hpp>
43 43
44 44
45 static const char* const KEY_ALPHABETIC = "Alphabetic"; 45 static const char* const KEY_ALPHABETIC = "Alphabetic";
46 static const char* const KEY_IDEOGRAPHIC = "Ideographic";
47 static const char* const KEY_PHONETIC = "Phonetic";
46 static const char* const KEY_BULK_DATA_URI = "BulkDataURI"; 48 static const char* const KEY_BULK_DATA_URI = "BulkDataURI";
47 static const char* const KEY_INLINE_BINARY = "InlineBinary"; 49 static const char* const KEY_INLINE_BINARY = "InlineBinary";
48 static const char* const KEY_SQ = "SQ"; 50 static const char* const KEY_SQ = "SQ";
51 static const char* const KEY_TAG = "tag";
49 static const char* const KEY_VALUE = "Value"; 52 static const char* const KEY_VALUE = "Value";
50 static const char* const KEY_VR = "vr"; 53 static const char* const KEY_VR = "vr";
51 54
52 55
53 namespace Orthanc 56 namespace Orthanc
54 { 57 {
55 #if ORTHANC_ENABLE_PUGIXML == 1 58 #if ORTHANC_ENABLE_PUGIXML == 1
59 static void DecomposeXmlPersonName(pugi::xml_node& target,
60 const std::string& source)
61 {
62 std::vector<std::string> tokens;
63 Toolbox::TokenizeString(tokens, source, '^');
64
65 if (tokens.size() >= 1)
66 {
67 target.append_child("FamilyName").text() = tokens[0].c_str();
68 }
69
70 if (tokens.size() >= 2)
71 {
72 target.append_child("GivenName").text() = tokens[1].c_str();
73 }
74
75 if (tokens.size() >= 3)
76 {
77 target.append_child("MiddleName").text() = tokens[2].c_str();
78 }
79
80 if (tokens.size() >= 4)
81 {
82 target.append_child("NamePrefix").text() = tokens[3].c_str();
83 }
84
85 if (tokens.size() >= 5)
86 {
87 target.append_child("NameSuffix").text() = tokens[4].c_str();
88 }
89 }
90
56 static void ExploreXmlDataset(pugi::xml_node& target, 91 static void ExploreXmlDataset(pugi::xml_node& target,
57 const Json::Value& source) 92 const Json::Value& source)
58 { 93 {
94 // http://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_F.3.html#table_F.3.1-1
59 assert(source.type() == Json::objectValue); 95 assert(source.type() == Json::objectValue);
60 96
61 Json::Value::Members members = source.getMemberNames(); 97 Json::Value::Members members = source.getMemberNames();
62 for (size_t i = 0; i < members.size(); i++) 98 for (size_t i = 0; i < members.size(); i++)
63 { 99 {
64 const DicomTag tag = FromDcmtkBridge::ParseTag(members[i]); 100 const DicomTag tag = FromDcmtkBridge::ParseTag(members[i]);
65 const Json::Value& content = source[members[i]]; 101 const Json::Value& content = source[members[i]];
66 102
67 assert(content.type() == Json::objectValue && 103 assert(content.type() == Json::objectValue &&
68 content.isMember("vr") && 104 content.isMember(KEY_VR) &&
69 content["vr"].type() == Json::stringValue); 105 content[KEY_VR].type() == Json::stringValue);
70 const std::string vr = content["vr"].asString(); 106 const std::string vr = content[KEY_VR].asString();
71 107
72 const std::string keyword = FromDcmtkBridge::GetTagName(tag, ""); 108 const std::string keyword = FromDcmtkBridge::GetTagName(tag, "");
73 109
74 pugi::xml_node node = target.append_child("DicomAttribute"); 110 pugi::xml_node node = target.append_child("DicomAttribute");
75 node.append_attribute("tag").set_value(members[i].c_str()); 111 node.append_attribute(KEY_TAG).set_value(members[i].c_str());
76 node.append_attribute("vr").set_value(vr.c_str()); 112 node.append_attribute(KEY_VR).set_value(vr.c_str());
77 113
78 if (keyword != std::string(DcmTag_ERROR_TagName)) 114 if (keyword != std::string(DcmTag_ERROR_TagName))
79 { 115 {
80 node.append_attribute("keyword").set_value(keyword.c_str()); 116 node.append_attribute("keyword").set_value(keyword.c_str());
81 } 117 }
97 ExploreXmlDataset(child, content[KEY_VALUE][j]); 133 ExploreXmlDataset(child, content[KEY_VALUE][j]);
98 } 134 }
99 } 135 }
100 if (vr == "PN") 136 if (vr == "PN")
101 { 137 {
102 if (content[KEY_VALUE][j].isMember(KEY_ALPHABETIC) && 138 bool hasAlphabetic = (content[KEY_VALUE][j].isMember(KEY_ALPHABETIC) &&
103 content[KEY_VALUE][j][KEY_ALPHABETIC].type() == Json::stringValue) 139 content[KEY_VALUE][j][KEY_ALPHABETIC].type() == Json::stringValue);
140
141 bool hasIdeographic = (content[KEY_VALUE][j].isMember(KEY_IDEOGRAPHIC) &&
142 content[KEY_VALUE][j][KEY_IDEOGRAPHIC].type() == Json::stringValue);
143
144 bool hasPhonetic = (content[KEY_VALUE][j].isMember(KEY_PHONETIC) &&
145 content[KEY_VALUE][j][KEY_PHONETIC].type() == Json::stringValue);
146
147 if (hasAlphabetic ||
148 hasIdeographic ||
149 hasPhonetic)
104 { 150 {
105 std::vector<std::string> tokens;
106 Toolbox::TokenizeString(tokens, content[KEY_VALUE][j][KEY_ALPHABETIC].asString(), '^');
107
108 pugi::xml_node child = node.append_child("PersonName"); 151 pugi::xml_node child = node.append_child("PersonName");
109 child.append_attribute("number").set_value(number.c_str()); 152 child.append_attribute("number").set_value(number.c_str());
110 153
111 pugi::xml_node name = child.append_child(KEY_ALPHABETIC); 154 if (hasAlphabetic)
112
113 if (tokens.size() >= 1)
114 { 155 {
115 name.append_child("FamilyName").text() = tokens[0].c_str(); 156 pugi::xml_node name = child.append_child(KEY_ALPHABETIC);
157 DecomposeXmlPersonName(name, content[KEY_VALUE][j][KEY_ALPHABETIC].asString());
116 } 158 }
117 159
118 if (tokens.size() >= 2) 160 if (hasIdeographic)
119 { 161 {
120 name.append_child("GivenName").text() = tokens[1].c_str(); 162 pugi::xml_node name = child.append_child(KEY_IDEOGRAPHIC);
163 DecomposeXmlPersonName(name, content[KEY_VALUE][j][KEY_IDEOGRAPHIC].asString());
121 } 164 }
122 165
123 if (tokens.size() >= 3) 166 if (hasPhonetic)
124 { 167 {
125 name.append_child("MiddleName").text() = tokens[2].c_str(); 168 pugi::xml_node name = child.append_child(KEY_PHONETIC);
126 } 169 DecomposeXmlPersonName(name, content[KEY_VALUE][j][KEY_PHONETIC].asString());
127
128 if (tokens.size() >= 4)
129 {
130 name.append_child("NamePrefix").text() = tokens[3].c_str();
131 }
132
133 if (tokens.size() >= 5)
134 {
135 name.append_child("NameSuffix").text() = tokens[4].c_str();
136 } 170 }
137 } 171 }
138 } 172 }
139 else 173 else
140 { 174 {
515 case ValueRepresentation_PersonName: 549 case ValueRepresentation_PersonName:
516 { 550 {
517 Json::Value value = Json::objectValue; 551 Json::Value value = Json::objectValue;
518 if (!tokens[i].empty()) 552 if (!tokens[i].empty())
519 { 553 {
520 value[KEY_ALPHABETIC] = tokens[i]; 554 std::vector<std::string> components;
555 Toolbox::TokenizeString(components, tokens[i], '=');
556
557 if (components.size() >= 1)
558 {
559 value[KEY_ALPHABETIC] = components[0];
560 }
561
562 if (components.size() >= 2)
563 {
564 value[KEY_IDEOGRAPHIC] = components[1];
565 }
566
567 if (components.size() >= 3)
568 {
569 value[KEY_PHONETIC] = components[2];
570 }
521 } 571 }
572
522 node[KEY_VALUE].append(value); 573 node[KEY_VALUE].append(value);
523 break; 574 break;
524 } 575 }
525 576
526 case ValueRepresentation_IntegerString: 577 case ValueRepresentation_IntegerString: