Vous avez reçu un message "Your GitLab account has been locked ..." ? Pas d'inquiétude : lisez cet article https://docs.gricad-pages.univ-grenoble-alpes.fr/help/unlock/

Commit eaf20d83 authored by EXT Arnaud Clère's avatar EXT Arnaud Clère
Browse files

WIP: Xml and QMetaObject support

parent 356da0d5
......@@ -53,7 +53,8 @@ HEADERS += \
QJson_impl.h \
QVariant_impl.h \
QModel_impl.h \
QData_impl.h
QData_impl.h \
QXml_impl.h
DISTFILES += \
persons.proto
......@@ -97,7 +97,7 @@ static QName qBindIgnoredBytes = "Ignored bytes" ;
//! QMetaData is optional data about current data to enable optimized processing (e.g. tag, , style, etc.) and/or transmission (QAbstractItemModel headers, CBOR tags, XML attribute, CSS, numpy.ndarray shapes, etc.)
using QMetaData = std::map<QName,QString>;
static const char* qmDataStreamVersion = "qmDataStreamVersion"; //!< Allows IBind support of QDataStream
static QName qmDataStreamVersion = "qmDataStreamVersion"; //!< Allows IBind support of QDataStream
// N-dimensional data structures for which specific IWriter may have optimized implementations
// BEWARE though that nested calls to IWriter are not guaranteed to follow the declared structure (this would prevent reusing general QBind functors for nested data structures)
......@@ -111,6 +111,9 @@ static QName qmSizes = "sizes" ; //!< comma-separated natural numbers
//! Sequence of records where item(qmNodes) contains children can be implemented as trees
static QName qmChildren = "children"; //!< name of a sequence of records with recursively the same name
//! Name of current data
static QName qmName = "name";
// //////////////////////////////////////////////////////////////////////////
// QBind<T,TResult>
......@@ -181,8 +184,10 @@ public:
/**/ Seq<T_> sequence( quint32 s) { return sequence(&s); }
/**/ Rec<T_> record ( quint32 s) { return record (&s); }
// Stream compatible shortcut
template<typename T> Seq<T_> operator<<(T&& t) { return sequence().bind(std::forward<T>(t)); }
// Shortcuts
template<typename T> Seq<T_> operator<<( T&& t) { return sequence().bind(std::forward<T>(t)); } // stream compatible
/**/ Rec<T_> record (QName n) { return meta({{qmName,n}}).record(); }
private:
T_ outer = T_(); //!< moved context of current traversal up to TResult that will point to the value itself (be it a QIODevice or QCborValue)
};
......
/****************************************************************************
* **
* ** Copyright (C) 2019 MinMaxMedical.
* ** All rights reserved.
* ** Contact: MinMaxMedical <InCAS@MinMaxMedical.com>
* **
* ** This file is part of the modmedLog module.
* **
* ** $QT_BEGIN_LICENSE:BSD$
* ** You may use this file under the terms of the BSD license as follows:
* **
* ** "Redistribution and use in source and binary forms, with or without
* ** modification, are permitted provided that the following conditions are
* ** met:
* ** * Redistributions of source code must retain the above copyright
* ** notice, this list of conditions and the following disclaimer.
* ** * Redistributions in binary form must reproduce the above copyright
* ** notice, this list of conditions and the following disclaimer in
* ** the documentation and/or other materials provided with the
* ** distribution.
* ** * Neither the name of MinMaxMedical S.A.S. and its Subsidiary(-ies) nor
* ** the names of its contributors may be used to endorse or promote
* ** products derived from this software without specific prior written
* ** permission.
* **
* ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
* ** $QT_END_LICENSE$
* **
* ****************************************************************************/
#pragma once
#include <type_traits>
#include <QtCore/qxmlstream.h>
#include "QBind_impl.h"
// //////////////////////////////////////////////////////////////////////////
// QBind<T,QXmlStreamWriter> support
//! \warning Since XML has no standard way of encoding data structures, we choose a rather implicit one
//! based on the fact that XML elements are implicit data structures unless they contain text without elements.
//! \li sequence : element named after outer item or metaData[qmName] or "sequence"
//! \li record : element named after outer item or metaData[qmName] or "record"
//! \li null : empty element named after outer item or metaData[qmName] or "item"
//! \li BindNative: text element named after outer item or metaData[qmName] or "item", containing the default text representation
class QXmlWriter : public IWriter
{
Q_DISABLE_COPY(QXmlWriter)
public:
QXmlWriter(QXmlStreamWriter* io) : io(io) { Q_ASSERT(io); }
BindMode mode() const noexcept { return BindMode::Write; }
// Shortcuts
Val<Cursor> value ( ) { return Cursor(this).value(); }
Val<Cursor> meta ( QMetaData&& m) { return Cursor(this).value().meta(m); }
Seq<Cursor> sequence(quint32* s=nullptr) { return Cursor(this).value().sequence(s); }
template<typename T> Cursor bind(T&& t) { return Cursor(this).value().bind(std::forward<T>(t)); }
protected:
bool _sequence(quint32* =nullptr) { io->writeStartElement(tag("sequence") ); att(); return true; }
bool _record (quint32* =nullptr) { io->writeStartElement(tag("record" ) ); att(); return true; }
bool _null ( ) { io->writeEmptyElement(tag("item" ) ); att(); return true; }
bool _bind ( const char* s) { io->writeTextElement (tag("item" ),s); att(); return true; }
bool _isOk() noexcept { return !io->hasError(); }
bool _out ( ) { io->writeEndElement(); return true; }
bool _item( ) { return true; }
bool _item(QName n) { name=n; return true; }
void _meta(QMetaData& m) { metaData.insert(m.cbegin(), m.cend()); auto n=metaData.find(qmName); if (n!=metaData.end()) { name=n->second; n->second=QString(); } }
private:
QString tag(QName def) { if (name.isNull()) return def; auto n=name; name=QString(); return n; }
void att() { for (auto a : metaData) { if (!a.second.isNull()) io->writeAttribute(a.first, a.second); } }
QXmlStreamWriter* io;
QMetaData metaData;
QString name;
};
......@@ -51,6 +51,7 @@
#include "QData_impl.h" // QDataReader, QDataWriter demonstrating a QDataStream with implicit types for benchmarking
#include "QVariant_impl.h" // QVariantBuilder, QVariantVisitor and QBind<QVariant,_> support
#include "QModel_impl.h" // Q*ModelWriter support
#include "QXml_impl.h" // QXmlWriter support
#ifdef PROTOBUF
#include "persons.pb.h"
......@@ -66,7 +67,24 @@
#include <QtWidgets/qapplication.h>
// //////////////////////////////////////////////////////////////////////////
// QBind<T,_> basic example using an internal bind method
// QBind-enabled types examples
// Using Qt's meta-object system
class Phone {
Q_GADGET
public:
enum Type { Mobile, Home, Office } type;
Q_ENUM(Type)
Q_PROPERTY(Type type MEMBER _t)
Q_PROPERTY(QString number MEMBER _n)
private:
Type _t;
QString _n;
};
// Using an internal bind method
struct Person
{
......@@ -75,7 +93,7 @@ struct Person
template<class TResult> //=Cursor
TResult bind(Val<TResult>&& value) { // works with value->mode()==Read as well as Write
return value
.record()
.record("Person")
.sequence("names")
.bind(firstName)
.bind( lastName)
......@@ -89,10 +107,7 @@ struct Person
}
};
Q_DECLARE_METATYPE(Person)
#include<QtCore/qdatastream.h>
QDataStream &operator<<(QDataStream &out, const Person &p)
{
return out
......@@ -114,9 +129,7 @@ QDataStream &operator>>(QDataStream &in, Person &p)
>> p.children;
}
// //////////////////////////////////////////////////////////////////////////
// QBind<T,_> example using an external bind method and special support for QDataStream using QMetaData
// Using an external bind method and special support for QDataStream using QMetaData
#include <QtGui/qcolor.h>
......@@ -191,38 +204,6 @@ public:
operator QUtf8String() const { return result.buffer(); }
};
// //////////////////////////////////////////////////////////////////////////
// QBind is not expected to easily map C++ types to XML schemas since there is no standard way to map data structures in XML
// The following is an example of simple XML format that can be used to transmit data to XML tools like XSLT to transform it into a specific XML schema
#include <QtCore/qxmlstream.h>
//! \see http://xml.calldei.com/JsonXML
class JsonXmlWriter : public IWriter
{
Q_DISABLE_COPY(JsonXmlWriter)
public:
JsonXmlWriter(QXmlStreamWriter* io) : io(io) { Q_ASSERT(io); }
template<typename T> Cursor bind(T&& t) { return Cursor(this).value().bind(std::forward<T>(t)); }
protected:
bool _sequence(quint32* =nullptr) { emptyLevel.push_back(true); io->writeStartElement("array" ); return true; }
bool _record (quint32* =nullptr) { emptyLevel.push_back(true); io->writeStartElement("object"); return true; }
bool _null ( ) { io->writeEmptyElement("null" ); return true; }
bool _bind ( const char* s) { io->writeTextElement ("string", s ); return true; }
bool _bind ( quint64&& n) { io->writeTextElement ("number", QString::number(n)); return true; }
bool _bind ( qint64&& n) { io->writeTextElement ("number", QString::number(n)); return true; }
bool _bind ( float&& n) { io->writeTextElement ("number", QString::number(n)); return true; }
bool _bind ( double&& n) { io->writeTextElement ("number", QString::number(n)); return true; }
bool _item(QName n) { if (!emptyLevel.back()) { io->writeEndElement(); } emptyLevel.back()=false; io->writeStartElement("member"); io->writeAttribute("name", n); return true; }
bool _item( ) { if (!emptyLevel.back()) { io->writeEndElement(); } emptyLevel.back()=false; io->writeStartElement("member"); return true; }
bool _out ( ) { if (!emptyLevel.back()) { io->writeEndElement(); } emptyLevel.pop_back() ; return true; }
private:
QXmlStreamWriter* io;
std::vector<bool> emptyLevel;
};
// //////////////////////////////////////////////////////////////////////////
// Tests and Benchmarks
......@@ -589,6 +570,14 @@ int main(int argc, char *argv[])
}
STOP("protobuf",QByteArray::fromStdString(buf).toHex());
#endif
START {
ba.clear();
QXmlStreamWriter w(&ba);
QXmlWriter d(&w);
d.bind(person);
w.writeEndDocument(); // FIXME
}
STOP("Xml",QString::fromUtf8(ba));
QBindable<> writable;
START {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment