はいそれでは表題の件やっていきます。
C++ GUI Programming with Qt4 348ページにはDOMを使った書き込みのほかにもう一つ方法があると書かれています。
We can generate XML by hand.
(テメェで書け)
だそうです。サンプルもQTextStreamを使ってそれはもうそのまんまXML書いていっているので、なんていうか...見るからにそのまんまなんでここで取り上げるのはやめます。(意味がないので)
なので以上です...というわけではありません。
C++ GUI Programming with Qt4にはさらに
http://doc.trolltech.com/qq/qq05-generating-xml.htmlにXML書き出しのQt3用のシンプルなクラス公開されていると書かれているので、それを今回はQt4用に変換して書いていこうと思います。
いつものようにQtCreaterの使用を前提とします。(QtCreaterなどの使い方は ”Qtをはじめよう" を見てください。)
なお、.proファイルに Qt += xml の記述をしておいてください。でなければQXml関連をコードに含められません。
ではコードを
(xmlwriter.h)
#include <qmap.h> #include <qstring.h> #include <qtextstream.h> #include <qtextcodec.h> class AttrMap : public QMap<QString, QString> { public: AttrMap() { } AttrMap( const QString& name, const QString& value ) { insert( name, value ); } }; class XmlWriter { public: XmlWriter( QIODevice *device, QTextCodec *codec = 0 ); ~XmlWriter(); void writeRaw( const QString& xml ); void writeString( const QString& string ); void writeOpenTag( const QString& name, const AttrMap& attrs = AttrMap() ); void writeCloseTag( const QString& name ); void writeAtomTag( const QString& name, const AttrMap& attrs = AttrMap() ); void writeTaggedString( const QString& name, const QString& string, const AttrMap& attrs = AttrMap() ); void newLine(); void setIndentSize( int size ) { indentSize = size; } void setAutoNewLine( bool on ) { autoNewLine = on; } private: QString protect( const QString& string ); QString opening( const QString& tag, const AttrMap& attrs = AttrMap() ); void writePendingIndent(); QTextStream out; QString indentStr; int indentSize; bool autoNewLine; bool atBeginningOfLine; };
(xmlwriter.cpp)
#include "xmlwriter.h" XmlWriter::XmlWriter( QIODevice *device, QTextCodec *codec ) : indentSize( 4 ), autoNewLine( false ), atBeginningOfLine( true ) { out.setDevice( device ); if ( codec == 0 ) { out.setCodec(QTextCodec::codecForName("UTF-8")); } else { out.setCodec( codec ); out << "<?xml version=\"1.0\" encoding=\"" << protect( codec->name() ) << "\"?>\n"; } } XmlWriter::~XmlWriter() { if ( autoNewLine && !atBeginningOfLine ) out << endl; } QString XmlWriter::protect( const QString& string ) { QString s = string; s.replace( "&", "&" ); s.replace( ">", ">" ); s.replace( "<", "<" ); s.replace( "\"", """ ); s.replace( "\'", "'" ); return s; } QString XmlWriter::opening( const QString& tag, const AttrMap& attrs ) { QString s = "<" + tag; AttrMap::ConstIterator a = attrs.begin(); while ( a != attrs.end() ) { s += " " + a.key() + "=\"" + protect( *a ) + "\""; ++a; } s += ">"; return s; } void XmlWriter::writePendingIndent() { if ( atBeginningOfLine ) { out << indentStr; atBeginningOfLine = false; } } void XmlWriter::newLine() { out << endl; atBeginningOfLine = true; } void XmlWriter::writeRaw( const QString& xml ) { out << xml; atBeginningOfLine = false; } void XmlWriter::writeString( const QString& string ) { out << protect( string ); atBeginningOfLine = false; } void XmlWriter::writeOpenTag( const QString& name, const AttrMap& attrs ) { writePendingIndent(); out << opening( name, attrs ); indentStr += QString().fill( ' ', indentSize ); if ( autoNewLine ) newLine(); } void XmlWriter::writeCloseTag( const QString& name ) { indentStr = indentStr.mid( indentSize ); writePendingIndent(); out << opening( "/" + name ); if ( autoNewLine ) newLine(); } void XmlWriter::writeAtomTag( const QString& name, const AttrMap& attrs ) { writePendingIndent(); QString atom = opening( name, attrs ); atom.insert( atom.length() - 1, "/" ); out << atom; if ( autoNewLine ) newLine(); } void XmlWriter::writeTaggedString( const QString& name, const QString& string, const AttrMap& attrs ) { writePendingIndent(); out << opening( name, attrs ); writeString( string ); out << opening( "/" + name ); if ( autoNewLine ) newLine(); }はいややこしいですね。めんどくさいのでサラッとしか説明しません。内部で何やってるか詳細に知りたい方は自分でヘッダ、cppを作成してこのコードをコピーしてそれぞれ動作を追ってください。
基本UTF-8、第2引数が指定された場合のみそのコーデックとなります。このクラスを使えば変換必須の文字(<とか)などを自動で変換し、またインデントなども処理してくれるので、全部自分で書くよりは楽ですね。
実行コードは以下のようになります。
(mainwindow.cpp)
#include "mainwindow.h" #include "ui_mainwindow.h" #include "xmlwriter.h" #include <QTextCodec> void MainWindow::writeProperty( XmlWriter& xw, const QString& name, const QString& type, const QString& value ) { xw.writeOpenTag( "property", AttrMap("name", name) ); xw.writeTaggedString( type, value ); xw.writeCloseTag( "property" ); } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QFile file("C:\\Users\\windows7\\Desktop\\test.txt"); if (file.open(QFile::WriteOnly| QFile::Truncate)) { QTextCodec::setCodecForTr( QTextCodec::codecForName("Shift-JIS")); XmlWriter xw( &file, QTextCodec::codecForName("Shift-JIS")); xw.setAutoNewLine( true ); xw.writeRaw( "<!DOCTYPE UI><UI version=\"3.1\">" ); xw.newLine(); xw.writeTaggedString( "class", tr("サンプル1") ); xw.writeOpenTag( tr("サンプルクラス"), AttrMap("class",tr( "サンプル1")) ); writeProperty( xw, "name", "string", tr("名前") ); writeProperty( xw, "caption", "string", tr("キャプション") ); xw.writeOpenTag( "element1-2" ); writeProperty( xw, "name", "string", "ElementName" ); writeProperty( xw, "text", "string", "Rock && Roll" ); xw.writeCloseTag( "element1-2" ); xw.writeCloseTag( tr("サンプルクラス") ); AttrMap attrs; attrs.insert( "spacing", "6" ); attrs.insert( "margin", "11" ); xw.writeAtomTag( "layoutdefaults", attrs ); xw.writeRaw( "</UI>" ); } file.close(); } MainWindow::~MainWindow() { delete ui; }はい微妙ですね。まぁXMLを全て自分で書くよりはマシになってますが、手間はDOMとあまり変わらないような感じがします。
これを実行して書き出されるXMLは以下の通りです。
(書き出されるXML)
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE UI><UI version="3.1"> <class>サンプル1</class> <サンプルクラス class="サンプル1"> <property name="name"> <string>名前</string> </property> <property name="caption"> <string>キャプション</string> </property> <element1-2> <property name="name"> <string>ElementName</string> </property> <property name="text"> <string>Rock && Roll</string> </property> </element1-2> </サンプルクラス> <layoutdefaults margin="11" spacing="6"/> </UI>以上です。