1 #include <sngxml/xml/XmlParserInterface.hpp>
2 #include <sngxml/xml/XmlContentHandler.hpp>
3 #include <sngxml/dom/Parser.hpp>
4 #include <sngxml/xpath/InitDone.hpp>
5 #include <sngxml/xpath/XPathEvaluate.hpp>
6 #include <sngxml/xpath/XPathDebug.hpp>
7 #include <soulng/lexer/TrivialLexer.hpp>
8 #include <soulng/util/Unicode.hpp>
9 #include <soulng/util/CodeFormatter.hpp>
10 #include <soulng/util/TextUtils.hpp>
11 #include <soulng/util/InitDone.hpp>
12 #include <iostream>
13
14 using namespace soulng::unicode;
15
16 class ContentHandler : public sngxml::xml::XmlContentHandler
17 {
18 public:
19 ContentHandler();
20 void StartDocument() override
21 {
22 formatter.WriteLine("*** start document ***");
23 }
24 void EndDocument() override
25 {
26 formatter.WriteLine("*** end document ***");
27 }
28 void Version(const std::u32string& xmlVersion) override
29 {
30 formatter.WriteLine("version: " + ToUtf8(xmlVersion));
31 }
32 void Standalone(bool standalone) override
33 {
34 std::string sd = "true";
35 if (!standalone)
36 {
37 sd = "false";
38 }
39 formatter.WriteLine("standalone: " + sd);
40 }
41 void Encoding(const std::u32string& encoding)
42 {
43 formatter.WriteLine("encoding: " + ToUtf8(encoding));
44 }
45 void Text(const std::u32string& text)
46 {
47 formatter.WriteLine("text: " + ToUtf8(text));
48 }
49 void Comment(const std::u32string& comment) override
50 {
51 formatter.WriteLine("comment: " + ToUtf8(comment));
52 }
53 void PI(const std::u32string& target, const std::u32string& data) override
54 {
55 formatter.WriteLine("PI: " + ToUtf8(target) + ": " + ToUtf8(data));
56 }
57 void CDataSection(const std::u32string& cdata) override
58 {
59 formatter.WriteLine("CDATA: " + ToUtf8(cdata));
60 }
61 void StartElement(const std::u32string& namespaceUri, const std::u32string& localName, const std::u32string& qualifiedName, const sngxml::xml::Attributes& attributes) override
62 {
63 formatter.WriteLine("start element:");
64 formatter.IncIndent();
65 formatter.WriteLine("ns: " + ToUtf8(namespaceUri));
66 formatter.WriteLine("local name: " + ToUtf8(localName));
67 formatter.WriteLine("qualified name: " + ToUtf8(qualifiedName));
68 formatter.WriteLine("attributes:");
69 formatter.IncIndent();
70 for (const sngxml::xml::Attribute& attr : attributes)
71 {
72 formatter.WriteLine("ns: " + ToUtf8(attr.NamespaceUri()));
73 formatter.WriteLine("local name: " + ToUtf8(attr.LocalName()));
74 formatter.WriteLine("qualified name: " + ToUtf8(attr.QualifiedName()));
75 formatter.WriteLine("value: " + ToUtf8(attr.Value()));
76 formatter.WriteLine("---");
77 }
78 formatter.DecIndent();
79 formatter.DecIndent();
80 }
81 void EndElement(const std::u32string& namespaceUri, const std::u32string& localName, const std::u32string& qualifiedName) override
82 {
83 formatter.WriteLine("end element:");
84 formatter.IncIndent();
85 formatter.WriteLine("ns: " + ToUtf8(namespaceUri));
86 formatter.WriteLine("local name: " + ToUtf8(localName));
87 formatter.WriteLine("qualified name: " + ToUtf8(qualifiedName));
88 formatter.DecIndent();
89 }
90 void SkippedEntity(const std::u32string& entityName)
91 {
92 formatter.WriteLine("skipped entity:" + ToUtf8(entityName));
93 }
94 private:
95 CodeFormatter formatter;
96 };
97
98 ContentHandler::ContentHandler() : formatter(std::cout)
99 {
100 }
101
102 void PrintUsage()
103 {
104 std::cout << "Usage: sngxmltester [options] ARGS..." << std::endl;
105 std::cout << "options:" << std::endl;
106 std::cout << "--help | -h" << std::endl;
107 std::cout << " Print help and exit." << std::endl;
108 std::cout << "--content <FILE.xml>| -c <FILE.xml>" << std::endl;
109 std::cout << " Parse given FILE.xml and print its contents to stdout using a content handler." << std::endl;
110 std::cout << "--dom <FILE.xml> | -m <FILE.xml>" << std::endl;
111 std::cout << " Read given FILE.xml into DOM document and then print the DOM document to stdout." << std::endl;
112 std::cout << "--xpath \"QUERY\" <FILE.xml> | -x \"QUERY\" <FILE.xml>" << std::endl;
113 std::cout << " Run given XPath query against FILE.xml and print the result." << std::endl;
114 std::cout << "--debug | -d" << std::endl;
115 std::cout << " Debug parsing and print parser debug XML log to stderr." << std::endl;
116 std::cout << " Note: parser debugging is enabled by default for debug build, sngxmltesterd.exe, only." << std::endl;
117 }
118
119 enum class Command
120 {
121 none, content, dom, xpath
122 };
123
124 struct Initializer
125 {
126 Initializer()
127 {
128 soulng::util::Init();
129 sngxml::xpath::Init();
130 }
131 ~Initializer()
132 {
133 sngxml::xpath::Done();
134 soulng::util::Done();
135 }
136 };
137
138 int main(int argc, const char** argv)
139 {
140 Initializer initializer;
141 try
142 {
143 std::vector<std::string> args;
144 bool debug = false;
145 Command command = Command::none;
146 for (int i = 1; i < argc; ++i)
147 {
148 std::string arg = argv[i];
149 if (StartsWith(arg, "--"))
150 {
151 if (arg == "--help")
152 {
153 PrintUsage();
154 return 1;
155 }
156 else if (arg == "--content")
157 {
158 command = Command::content;
159 }
160 else if (arg == "--dom")
161 {
162 command = Command::dom;
163 }
164 else if (arg == "--xpath")
165 {
166 command = Command::xpath;
167 }
168 else if (arg == "--debug")
169 {
170 debug = true;
171 }
172 else
173 {
174 throw std::runtime_error("unknown option '" + arg + "'");
175 }
176 }
177 else if (StartsWith(arg, "-"))
178 {
179 std::string options = arg.substr(1);
180 if (options.empty())
181 {
182 throw std::runtime_error("unknown option '-" + arg + "'");
183 }
184 for (char o : options)
185 {
186 if (o == 'h')
187 {
188 PrintUsage();
189 return 1;
190 }
191 else if (o == 'c')
192 {
193 command = Command::content;
194 }
195 else if (o == 'm')
196 {
197 command = Command::dom;
198 }
199 else if (o == 'x')
200 {
201 command = Command::xpath;
202 }
203 else if (o == 'd')
204 {
205 debug = true;
206 }
207 else
208 {
209 throw std::runtime_error("unknown option '-" + std::string(1, o) + "'");
210 }
211 }
212 }
213 else
214 {
215 args.push_back(arg);
216 }
217 }
218 if (args.empty() || command == Command::none)
219 {
220 PrintUsage();
221 return 1;
222 }
223 if (command == Command::content)
224 {
225 sngxml::xml::Flags flags = sngxml::xml::Flags::none;
226 if (debug)
227 {
228 flags = flags | sngxml::xml::Flags::debug;
229 }
230 for (const std::string& xmlFileName : args)
231 {
232 std::cout << "> " << xmlFileName << std::endl;
233 ContentHandler contentHandler;
234 sngxml::xml::ParseXmlFile(xmlFileName, &contentHandler, flags);
235 }
236 }
237 else if (command == Command::dom)
238 {
239 sngxml::dom::Flags flags = sngxml::dom::Flags::none;
240 if (debug)
241 {
242 flags = flags | sngxml::dom::Flags::debug;
243 }
244 for (const std::string& xmlFileName : args)
245 {
246 std::cout << "> " << xmlFileName << std::endl;
247 std::unique_ptr<sngxml::dom::Document> doc = sngxml::dom::ReadDocument(xmlFileName, flags);
248 CodeFormatter formatter(std::cout);
249 doc->Write(formatter);
250 }
251 }
252 else if (command == Command::xpath)
253 {
254 if (args.size() != 2)
255 {
256 throw std::runtime_error("wrong number of args");
257 }
258 if (debug)
259 {
260 sngxml::xpath::SetXPathDebugParsing();
261 sngxml::xpath::SetXPathDebugQuery();
262 }
263 std::string query = args[0];
264 std::string xmlFileName = args[1];
265 std::cout << "> " << xmlFileName << std::endl;
266 std::unique_ptr<sngxml::dom::Document> doc = sngxml::dom::ReadDocument(xmlFileName);
267 std::unique_ptr<sngxml::xpath::XPathObject> xpathObject = sngxml::xpath::Evaluate(soulng::unicode::ToUtf32(query), doc.get());
268 if (debug)
269 {
270 std::unique_ptr<sngxml::dom::Node> queryNode = sngxml::xpath::GetXPathQueryDom();
271 if (queryNode)
272 {
273 CodeFormatter formatter(std::cerr);
274 formatter.SetIndentSize(1);
275 formatter.WriteLine("query:");
276 queryNode->Write(formatter);
277 }
278 }
279 if (xpathObject)
280 {
281 std::unique_ptr<sngxml::dom::Node> resultNode = xpathObject->ToDom();
282 if (resultNode)
283 {
284 CodeFormatter formatter(std::cout);
285 formatter.SetIndentSize(1);
286 resultNode->Write(formatter);
287 }
288 }
289 }
290 else
291 {
292 throw std::runtime_error("unknown command");
293 }
294 }
295 catch (const std::exception& ex;)
296 {
297 std::cerr << ex.what() << std::endl;
298 return 1;
299 }
300 return 0;
301 }