int main(int argc, char **argv) { enum ExitCode { /** * We start from 2, because QApplicationArgumentParser * uses 1. */ QueryFailure = 2, StdOutFailure }; const QCoreApplication app(argc, argv); QCoreApplication::setApplicationName(QLatin1String("xmlpatterns")); QXmlNamePool namePool; PatternistApplicationParser parser(argc, argv, namePool); parser.setApplicationDescription(QLatin1String("A tool for running XQuery queries.")); parser.setApplicationVersion(QLatin1String("0.1")); QApplicationArgument param(QLatin1String("param"), QXmlPatternistCLI::tr("Binds an external variable. The value is directly available using the variable reference: $name."), qMetaTypeId<Parameter>()); param.setMaximumOccurrence(-1); parser.addArgument(param); const QApplicationArgument noformat(QLatin1String("no-format"), QXmlPatternistCLI::tr("By default output is formatted for readability. When specified, strict serialization is performed.")); parser.addArgument(noformat); const QApplicationArgument isURI(QLatin1String("is-uri"), QXmlPatternistCLI::tr("If specified, all filenames on the command line are interpreted as URIs instead of a local filenames.")); parser.addArgument(isURI); const QApplicationArgument initialTemplateName(QLatin1String("initial-template"), QXmlPatternistCLI::tr("The name of the initial template to call as a Clark Name."), QVariant::String); parser.addArgument(initialTemplateName); /* The temporary object is required to compile with g++ 3.3. */ QApplicationArgument queryURI = QApplicationArgument(QLatin1String("query/stylesheet"), QXmlPatternistCLI::tr("A local filename pointing to the query to run. If the name ends with .xsl it's assumed " "to be an XSL-T stylesheet. If it ends with .xq, it's assumed to be an XQuery query. (In " "other cases it's also assumed to be an XQuery query, but that interpretation may " "change in a future release of Qt.)"), QVariant::String); queryURI.setMinimumOccurrence(1); queryURI.setNameless(true); parser.addArgument(queryURI); QApplicationArgument focus = QApplicationArgument(QLatin1String("focus"), QXmlPatternistCLI::tr("The document to use as focus. Mandatory " "in case a stylesheet is used. This option is " "also affected by the is-uris option."), QVariant::String); focus.setMinimumOccurrence(0); focus.setNameless(true); parser.addArgument(focus); QApplicationArgument output(QLatin1String("output"), QXmlPatternistCLI::tr("A local file to which the output should be written. " "The file is overwritten, or if not exist, created. " "If absent, stdout is used."), qMetaTypeId<QIODevice *>()); parser.addArgument(output); if(!parser.parse()) return parser.exitCode(); /* Get the query URI. */ const QUrl effectiveURI(finalizeURI(parser, isURI, queryURI)); QXmlQuery::QueryLanguage lang; if(effectiveURI.toString().endsWith(QLatin1String(".xsl"))) lang = QXmlQuery::XSLT20; else lang = QXmlQuery::XQuery10; if(lang == QXmlQuery::XQuery10 && parser.has(initialTemplateName)) { parser.message(QXmlPatternistCLI::tr("An initial template name cannot be specified when running an XQuery.")); return QApplicationArgumentParser::ParseError; } QXmlQuery query(lang, namePool); query.setInitialTemplateName(qvariant_cast<QXmlName>(parser.value(initialTemplateName))); /* Bind external variables. */ { const QVariantList parameters(parser.values(param)); const int len = parameters.count(); /* For tracking duplicates. */ QSet<QString> usedParameters; for(int i = 0; i < len; ++i) { const Parameter p(qvariant_cast<Parameter>(parameters.at(i))); if(usedParameters.contains(p.first)) { parser.message(QXmlPatternistCLI::tr("Each parameter must be unique, %1 is specified at least twice.").arg(p.first)); return QApplicationArgumentParser::ParseError; } else { usedParameters.insert(p.first); query.bindVariable(p.first, QXmlItem(p.second)); } } } if(parser.has(focus)) { if(!query.setFocus(finalizeURI(parser, isURI, focus))) return QueryFailure; } else if(lang == QXmlQuery::XSLT20 && !parser.has(initialTemplateName)) { parser.message(QXmlPatternistCLI::tr("When a stylesheet is used, a " "document must be specified as a focus, or an " "initial template name must be specified, or both.")); return QApplicationArgumentParser::ParseError; } query.setQuery(effectiveURI); const QPatternist::AutoPtr<QIODevice> outDevice(qvariant_cast<QIODevice *>(parser.value(output))); Q_ASSERT(outDevice); Q_ASSERT(outDevice->isWritable()); if(query.isValid()) { typedef QPatternist::AutoPtr<QAbstractXmlReceiver> RecPtr; RecPtr receiver; if(parser.has(noformat)) receiver = RecPtr(new QXmlSerializer(query, outDevice.data())); else receiver = RecPtr(new QXmlFormatter(query, outDevice.data())); const bool success = query.evaluateTo(receiver.data()); if(success) return parser.exitCode(); else return QueryFailure; } else return QueryFailure; }
int main(int argc, char **argv) { enum ExitCode { /** * We start from 2, because QApplicationArgumentParser * uses 1. */ QueryFailure = 2, StdOutFailure }; const QCoreApplication app(argc, argv); QCoreApplication::setApplicationName(QLatin1String("xmlpatterns")); PatternistApplicationParser parser(argc, argv); parser.setApplicationDescription(QLatin1String("A tool for running XQuery queries.")); parser.setApplicationVersion(QLatin1String("0.1")); /* Is there a better way to do this? Probably not, but if the class becomes public, we probably * want a helper function that wraps this hack. */ const int parameterType = qVariantFromValue(Parameter()).userType(); const int outputType = qVariantFromValue(static_cast<QIODevice *>(0)).userType(); QApplicationArgument param(QLatin1String("param"), QXmlPatternistCLI::tr("Binds an external variable. The value is directly available using the variable reference: $name."), parameterType); param.setMaximumOccurrence(-1); parser.addArgument(param); const QApplicationArgument noformat(QLatin1String("no-format"), QXmlPatternistCLI::tr("By default output is formatted for readability. When specified, strict serialization is performed.")); parser.addArgument(noformat); const QApplicationArgument isURI(QLatin1String("is-uri"), QXmlPatternistCLI::tr("If specified, the filename is interpreted as a URI instead of a local filename.")); parser.addArgument(isURI); /* The temporary object is required to compile with g++ 3.3. */ QApplicationArgument queryURI = QApplicationArgument(QString(), /* Nameless. */ QXmlPatternistCLI::tr("A local filename pointing to the query to run. " "If the name ends with .xq it's assumed " "to be an XQuery query. (In other cases too, but " "that interpretation may change in a future release of Qt.)"), QVariant::String); queryURI.setMinimumOccurrence(1); parser.addArgument(queryURI); QApplicationArgument output(QLatin1String("output"), QXmlPatternistCLI::tr("A local file to which the output should be written. The file is overwritten, or if not exist, created. If absent, stdout is used."), outputType); parser.addArgument(output); if(!parser.parse()) return parser.exitCode(); QXmlQuery query; /* Bind external variables. */ { const QVariantList parameters(parser.values(param)); const int len = parameters.count(); for(int i = 0; i < len; ++i) { const Parameter p(qVariantValue<Parameter>(parameters.at(i))); query.bindVariable(p.first, QXmlItem(p.second)); } } /* The final preparations and execute the query. */ QPatternist::ColoringMessageHandler messageHandler; query.setMessageHandler(&messageHandler); /* Get the query URI. */ QUrl userURI; { const QString stringURI(parser.value(queryURI).toString()); if(parser.has(isURI)) userURI = QUrl::fromEncoded(stringURI.toLatin1()); else userURI = QUrl::fromLocalFile(stringURI); } const QUrl effectiveURI(QUrl::fromLocalFile(QDir::current().absolutePath() + QLatin1Char('/')).resolved(userURI)); Q_ASSERT_X(userURI.isValid(), Q_FUNC_INFO, "QApplicationArgumentParser should promise us this."); query.setQuery(effectiveURI); QIODevice *const outDevice = qVariantValue<QIODevice *>(parser.value(output)); Q_ASSERT(outDevice); Q_ASSERT(outDevice->isWritable()); if(query.isValid()) { QAbstractXmlReceiver *receiver = 0; if(parser.has(noformat)) receiver = new QXmlSerializer(query, outDevice); else receiver = new QXmlFormatter(query, outDevice); const bool success = query.evaluateTo(receiver); delete outDevice; delete receiver; if(success) return parser.exitCode(); else return QueryFailure; } else { delete outDevice; return QueryFailure; } }