PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
query_scu::result_formatter Class Reference

Result formatter for query results. More...

#include <result_formatter.h>

Collaboration diagram for query_scu::result_formatter:
Collaboration graph

Classes

struct  column_def
 Column definition for formatting. More...
 

Public Types

using query_level = kcenon::pacs::services::query_level
 

Public Member Functions

 result_formatter (output_format format, query_level level)
 Construct formatter with output format.
 
std::string format (const std::vector< kcenon::pacs::core::dicom_dataset > &results) const
 Format query results.
 

Private Member Functions

std::string format_table (const std::vector< kcenon::pacs::core::dicom_dataset > &results) const
 Format results as a human-readable table.
 
std::string format_json (const std::vector< kcenon::pacs::core::dicom_dataset > &results) const
 Format results as JSON.
 
std::string format_csv (const std::vector< kcenon::pacs::core::dicom_dataset > &results) const
 Format results as CSV.
 
std::vector< column_defget_columns_for_level () const
 Get columns appropriate for the query level.
 

Static Private Member Functions

static std::string get_tag_value (const kcenon::pacs::core::dicom_dataset &ds, kcenon::pacs::core::dicom_tag tag)
 Get tag value from dataset as string.
 
static std::string escape_json (const std::string &s)
 Escape string for JSON output.
 
static std::string escape_csv (const std::string &s)
 Escape string for CSV output.
 

Private Attributes

output_format format_
 
query_level level_
 

Detailed Description

Result formatter for query results.

Formats C-FIND query results for display in different output formats.

Examples
query_scu/main.cpp.

Definition at line 52 of file result_formatter.h.

Member Typedef Documentation

◆ query_level

Constructor & Destructor Documentation

◆ result_formatter()

query_scu::result_formatter::result_formatter ( output_format format,
query_level level )
inlineexplicit

Construct formatter with output format.

Parameters
formatThe output format to use
levelThe query level for proper column selection

Definition at line 61 of file result_formatter.h.

62 : format_(format), level_(level) {}

Member Function Documentation

◆ escape_csv()

static std::string query_scu::result_formatter::escape_csv ( const std::string & s)
inlinestaticnodiscardprivate

Escape string for CSV output.

Definition at line 325 of file result_formatter.h.

325 {
326 if (s.find_first_of(",\"\n\r") == std::string::npos) {
327 return s;
328 }
329
330 std::string result = "\"";
331 for (char c : s) {
332 if (c == '"') {
333 result += "\"\"";
334 } else {
335 result += c;
336 }
337 }
338 result += "\"";
339 return result;
340 }

Referenced by format_csv().

Here is the caller graph for this function:

◆ escape_json()

static std::string query_scu::result_formatter::escape_json ( const std::string & s)
inlinestaticnodiscardprivate

Escape string for JSON output.

Definition at line 295 of file result_formatter.h.

295 {
296 std::string result;
297 result.reserve(s.length());
298 for (char c : s) {
299 switch (c) {
300 case '"': result += "\\\""; break;
301 case '\\': result += "\\\\"; break;
302 case '\b': result += "\\b"; break;
303 case '\f': result += "\\f"; break;
304 case '\n': result += "\\n"; break;
305 case '\r': result += "\\r"; break;
306 case '\t': result += "\\t"; break;
307 default:
308 if (static_cast<unsigned char>(c) < 0x20) {
309 result += "\\u";
310 char buf[5];
311 std::snprintf(buf, sizeof(buf), "%04X",
312 static_cast<unsigned char>(c));
313 result += buf;
314 } else {
315 result += c;
316 }
317 }
318 }
319 return result;
320 }

Referenced by format_json().

Here is the caller graph for this function:

◆ format()

std::string query_scu::result_formatter::format ( const std::vector< kcenon::pacs::core::dicom_dataset > & results) const
inlinenodiscard

Format query results.

Parameters
resultsVector of result datasets
Returns
Formatted string output
Examples
query_scu/main.cpp.

Definition at line 69 of file result_formatter.h.

70 {
71 switch (format_) {
73 return format_json(results);
75 return format_csv(results);
77 default:
78 return format_table(results);
79 }
80 }
std::string format_csv(const std::vector< kcenon::pacs::core::dicom_dataset > &results) const
Format results as CSV.
std::string format_table(const std::vector< kcenon::pacs::core::dicom_dataset > &results) const
Format results as a human-readable table.
std::string format_json(const std::vector< kcenon::pacs::core::dicom_dataset > &results) const
Format results as JSON.
@ json
JSON format for integration.
@ csv
CSV format for export.
@ table
Human-readable table format.

References query_scu::csv, format_, format_csv(), format_json(), format_table(), query_scu::json, and query_scu::table.

Here is the call graph for this function:

◆ format_csv()

std::string query_scu::result_formatter::format_csv ( const std::vector< kcenon::pacs::core::dicom_dataset > & results) const
inlinenodiscardprivate

Format results as CSV.

Definition at line 197 of file result_formatter.h.

198 {
199 using namespace kcenon::pacs::core;
200 std::ostringstream oss;
201
203
204 // Print header row
205 for (size_t i = 0; i < columns.size(); ++i) {
206 oss << columns[i].header;
207 if (i < columns.size() - 1) {
208 oss << ",";
209 }
210 }
211 oss << "\n";
212
213 // Print data rows
214 for (const auto& result : results) {
215 for (size_t i = 0; i < columns.size(); ++i) {
216 auto value = get_tag_value(result, columns[i].tag);
217 oss << escape_csv(value);
218 if (i < columns.size() - 1) {
219 oss << ",";
220 }
221 }
222 oss << "\n";
223 }
224
225 return oss.str();
226 }
static std::string get_tag_value(const kcenon::pacs::core::dicom_dataset &ds, kcenon::pacs::core::dicom_tag tag)
Get tag value from dataset as string.
std::vector< column_def > get_columns_for_level() const
Get columns appropriate for the query level.
static std::string escape_csv(const std::string &s)
Escape string for CSV output.
constexpr dicom_tag columns
Columns.

References escape_csv(), get_columns_for_level(), and get_tag_value().

Referenced by format().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ format_json()

std::string query_scu::result_formatter::format_json ( const std::vector< kcenon::pacs::core::dicom_dataset > & results) const
inlinenodiscardprivate

Format results as JSON.

Definition at line 155 of file result_formatter.h.

156 {
157 using namespace kcenon::pacs::core;
158 std::ostringstream oss;
159
160 oss << "{\n";
161 oss << " \"queryLevel\": \"" << kcenon::pacs::services::to_string(level_) << "\",\n";
162 oss << " \"resultCount\": " << results.size() << ",\n";
163 oss << " \"results\": [\n";
164
166
167 for (size_t i = 0; i < results.size(); ++i) {
168 const auto& result = results[i];
169 oss << " {\n";
170
171 for (size_t j = 0; j < columns.size(); ++j) {
172 auto value = get_tag_value(result, columns[j].tag);
173 oss << " \"" << columns[j].json_key << "\": \""
174 << escape_json(value) << "\"";
175 if (j < columns.size() - 1) {
176 oss << ",";
177 }
178 oss << "\n";
179 }
180
181 oss << " }";
182 if (i < results.size() - 1) {
183 oss << ",";
184 }
185 oss << "\n";
186 }
187
188 oss << " ]\n";
189 oss << "}\n";
190
191 return oss.str();
192 }
static std::string escape_json(const std::string &s)
Escape string for JSON output.
auto to_string(mpps_status status) -> std::string_view
Convert mpps_status to DICOM string representation.
Definition mpps_scp.h:60

References escape_json(), get_columns_for_level(), get_tag_value(), level_, and kcenon::pacs::services::to_string().

Referenced by format().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ format_table()

std::string query_scu::result_formatter::format_table ( const std::vector< kcenon::pacs::core::dicom_dataset > & results) const
inlinenodiscardprivate

Format results as a human-readable table.

Definition at line 86 of file result_formatter.h.

87 {
88 using namespace kcenon::pacs::core;
89 std::ostringstream oss;
90
91 if (results.empty()) {
92 oss << "No results found.\n";
93 return oss.str();
94 }
95
96 // Define columns based on query level
98
99 // Calculate column widths
100 std::vector<size_t> widths;
101 widths.reserve(columns.size());
102 for (const auto& col : columns) {
103 widths.push_back(col.header.length());
104 }
105
106 // Update widths based on data
107 for (const auto& result : results) {
108 for (size_t i = 0; i < columns.size(); ++i) {
109 auto value = get_tag_value(result, columns[i].tag);
110 widths[i] = std::max(widths[i], value.length());
111 }
112 }
113
114 // Cap widths at reasonable maximum
115 for (auto& w : widths) {
116 w = std::min(w, size_t(40));
117 }
118
119 // Print header
120 oss << "\n=== Query Results (" << results.size() << " "
121 << kcenon::pacs::services::to_string(level_) << "(s)) ===\n\n";
122
123 // Print column headers
124 for (size_t i = 0; i < columns.size(); ++i) {
125 oss << std::left << std::setw(static_cast<int>(widths[i] + 2))
126 << columns[i].header;
127 }
128 oss << "\n";
129
130 // Print separator
131 for (size_t i = 0; i < columns.size(); ++i) {
132 oss << std::string(widths[i], '-') << " ";
133 }
134 oss << "\n";
135
136 // Print data rows
137 for (const auto& result : results) {
138 for (size_t i = 0; i < columns.size(); ++i) {
139 auto value = get_tag_value(result, columns[i].tag);
140 if (value.length() > widths[i]) {
141 value = value.substr(0, widths[i] - 3) + "...";
142 }
143 oss << std::left << std::setw(static_cast<int>(widths[i] + 2))
144 << value;
145 }
146 oss << "\n";
147 }
148
149 return oss.str();
150 }

References get_columns_for_level(), get_tag_value(), level_, and kcenon::pacs::services::to_string().

Referenced by format().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_columns_for_level()

std::vector< column_def > query_scu::result_formatter::get_columns_for_level ( ) const
inlinenodiscardprivate

Get columns appropriate for the query level.

Definition at line 240 of file result_formatter.h.

240 {
241 using namespace kcenon::pacs::core;
242 std::vector<column_def> columns;
243
244 // Patient level columns (always included)
245 columns.push_back({"Patient Name", tags::patient_name, "patientName"});
246 columns.push_back({"Patient ID", tags::patient_id, "patientId"});
247
248 if (level_ == query_level::patient) {
249 columns.push_back({"Birth Date", tags::patient_birth_date, "birthDate"});
250 columns.push_back({"Sex", tags::patient_sex, "sex"});
251 return columns;
252 }
253
254 // Study level columns
255 columns.push_back({"Study Date", tags::study_date, "studyDate"});
256 columns.push_back({"Accession #", tags::accession_number, "accessionNumber"});
257 columns.push_back({"Description", tags::study_description, "studyDescription"});
258
259 if (level_ == query_level::study) {
260 columns.push_back({"Modalities", tags::modalities_in_study, "modalities"});
261 columns.push_back({"Study UID", tags::study_instance_uid, "studyInstanceUid"});
262 return columns;
263 }
264
265 // Series level columns
266 columns.push_back({"Modality", tags::modality, "modality"});
267 columns.push_back({"Series #", tags::series_number, "seriesNumber"});
268 columns.push_back({"Series Desc", tags::series_description, "seriesDescription"});
269
270 if (level_ == query_level::series) {
271 columns.push_back({"Series UID", tags::series_instance_uid, "seriesInstanceUid"});
272 return columns;
273 }
274
275 // Instance level columns
276 columns.push_back({"Instance #", tags::instance_number, "instanceNumber"});
277 columns.push_back({"SOP Class", tags::sop_class_uid, "sopClassUid"});
278 columns.push_back({"SOP Instance UID", tags::sop_instance_uid, "sopInstanceUid"});
279
280 return columns;
281 }

References level_.

Referenced by format_csv(), format_json(), and format_table().

Here is the caller graph for this function:

◆ get_tag_value()

static std::string query_scu::result_formatter::get_tag_value ( const kcenon::pacs::core::dicom_dataset & ds,
kcenon::pacs::core::dicom_tag tag )
inlinestaticnodiscardprivate

Get tag value from dataset as string.

Definition at line 286 of file result_formatter.h.

288 {
289 return ds.get_string(tag);
290 }
auto get_string(dicom_tag tag, std::string_view default_value="") const -> std::string
Get the string value of an element.

References kcenon::pacs::core::dicom_dataset::get_string().

Referenced by format_csv(), format_json(), and format_table().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ format_

output_format query_scu::result_formatter::format_
private

Definition at line 342 of file result_formatter.h.

Referenced by format().

◆ level_

query_level query_scu::result_formatter::level_
private

Definition at line 343 of file result_formatter.h.

Referenced by format_json(), format_table(), and get_columns_for_level().


The documentation for this class was generated from the following file: