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& targetconst 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& namespaceUriconst std::u32string& localNameconst std::u32string& qualifiedNameconst 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& namespaceUriconst std::u32string& localNameconst 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     nonecontentdomxpath
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 argcconst 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(1o) + "'");
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&contentHandlerflags);
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(xmlFileNameflags);
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 }