33 namespace out { |
33 namespace out { |
34 namespace yaml { |
34 namespace yaml { |
35 |
35 |
36 class YAMLHandler : public relpipe::reader::handlers::RelationalReaderStringHandler { |
36 class YAMLHandler : public relpipe::reader::handlers::RelationalReaderStringHandler { |
37 private: |
37 private: |
|
38 const char ESC = '\\'; |
|
39 const char Q = '"'; |
38 std::ostream& output; |
40 std::ostream& output; |
39 std::wstring_convert<std::codecvt_utf8<wchar_t>> convertor; // we generate YAML always in UTF-8 like XML? |
41 std::wstring_convert<std::codecvt_utf8<wchar_t>> convertor; // we generate YAML always in UTF-8 like XML? |
40 std::vector<relpipe::reader::handlers::AttributeMetadata> currentAttributes; |
42 std::vector<relpipe::reader::handlers::AttributeMetadata> currentAttributes; |
41 size_t currentAttributeIndex = 0; |
43 size_t currentAttributeIndex = 0; |
|
44 bool firstRecord; |
42 |
45 |
43 void writeYamlValue(const relpipe::common::type::StringX& value) { |
46 std::string escape(const relpipe::common::type::StringX& value) { |
44 // TODO: escaping |
47 std::stringstream result; |
45 output << convertor.to_bytes(value); |
48 result.put(Q); |
|
49 for (char ch : convertor.to_bytes(value)) { |
|
50 if (ch == Q) result.put(ESC).put(ch); |
|
51 else result.put(ch); |
|
52 } |
|
53 result.put(Q); |
|
54 return result.str(); |
46 } |
55 } |
|
56 |
|
57 std::string indent(int level) { |
|
58 std::stringstream result; |
|
59 for (int i = 0; i < level; i++) result << " "; |
|
60 return result.str(); |
|
61 } |
|
62 |
47 public: |
63 public: |
48 |
64 |
49 YAMLHandler(std::ostream& output) : output(output) { |
65 YAMLHandler(std::ostream& output) : output(output) { |
50 } |
66 } |
51 |
67 |
52 void startRelation(relpipe::common::type::StringX name, std::vector<relpipe::reader::handlers::AttributeMetadata> attributes) override { |
68 void startRelation(relpipe::common::type::StringX name, std::vector<relpipe::reader::handlers::AttributeMetadata> attributes) override { |
53 currentAttributes = attributes; |
69 currentAttributes = attributes; |
|
70 currentAttributeIndex = 0; |
|
71 output << escape(name); |
|
72 output << ":" << std::endl; |
|
73 output << indent(1) << R"("attribute-metadata":)" << std::endl; |
|
74 for (auto am : attributes) output << indent(2) << R"(- "name": )" << escape(am.getAttributeName()) << std::endl << indent(2) << R"( "type": )" << escape(am.getTypeName()) << std::endl; |
|
75 firstRecord = true; |
54 } |
76 } |
55 |
77 |
56 void attribute(const relpipe::common::type::StringX& value) override { |
78 void attribute(const relpipe::common::type::StringX& value) override { |
|
79 if (firstRecord) { |
|
80 output << indent(1) << R"("record":)" << std::endl; |
|
81 firstRecord = false; |
|
82 } |
|
83 |
57 if (currentAttributeIndex % currentAttributes.size() == 0) { |
84 if (currentAttributeIndex % currentAttributes.size() == 0) { |
58 currentAttributeIndex = 0; |
85 currentAttributeIndex = 0; |
59 |
86 output << indent(2) << "- "; |
60 } else { |
87 } else { |
61 |
88 output << indent(2) << " "; |
62 } |
89 } |
|
90 |
|
91 output << escape(currentAttributes[currentAttributeIndex].getAttributeName()) << ": "; |
|
92 output << escape(value) << std::endl; |
63 |
93 |
64 currentAttributeIndex++; |
94 currentAttributeIndex++; |
65 } |
95 } |
66 |
96 |
67 void endOfPipe() { |
97 void endOfPipe() { |