Coro で Producer-Consumer パターン
増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編 を参考に Coro で Producer-Consumer パターンを実装。
Producer-Consumer パターン は メッセージキューだが、キューが一杯のときはキューに入れようとする待たされる。キューが空のときキューを読もうとすると待たされる。
#!/usr/bin/perl use strict; use warnings; package Maker; use Coro; use Coro::Timer; sub new { my ( $class, %args ) = @_; bless \%args, $class; } sub run { my $self = shift; my $coro = async { do { my $queue = $self->{queue}; my $msg; $msg = "message1"; print "Maker: put $msg\n"; $queue->put($msg); $msg = "message2"; print "Maker: put $msg\n"; $queue->put($msg); $msg = "message3"; print "Maker: put $msg\n"; $queue->put($msg); $msg = "message4"; print "Maker: put $msg\n"; $queue->put($msg); $msg = "end"; print "Maker: put $msg\n"; $queue->put($msg); }; }; } package Eater; use Coro; sub new { my ( $class, %args ) = @_; bless \%args, $class; } sub run { my $self = shift; my $coro = async { do { my $queue = $self->{queue}; while (1) { my $msg = $queue->take; print "Eater: take $msg\n"; last if $msg =~ m/^end$/; } }; }; return $coro; } package Queue; use Coro; use Coro::Semaphore; use Coro::Signal; sub new { my ( $class, %args ) = @_; my %defaults = ( max => 3 ); %args = ( %defaults, %args ); $args{signal} = Coro::Signal->new; $args{queue} = []; $args{put_sem} = Coro::Semaphore->new; $args{take_sem} = Coro::Semaphore->new; bless \%args, $class; } sub put { my $self = shift; my $guard = $self->{put_sem}->guard(); while ( $self->{max} <= scalar( @{ $self->{queue} } ) ) { print qq{no space on the table. waiting for "put"\n}; $self->{signal}->wait(); } push @{ $self->{queue} }, $_[0]; $self->{signal}->broadcast(); } sub take { my $self = shift; my $guard = $self->{take_sem}->guard(); while ( scalar( @{ $self->{queue} } ) == 0 ) { print qq{no cake on the table. waiting for "put"\n}; $self->{signal}->wait(); } my $ret = shift @{ $self->{queue} }; $self->{signal}->broadcast(); return $ret; } package main; use Coro; my $queue = Queue->new( max => 3 ); my $eater = Eater->new( queue => $queue ); my $maker = Maker->new( queue => $queue ); my $maker_coro = $maker->run(); my $eater_coro = $eater->run(); $maker_coro->join(); $eater_coro->join();
出力
Maker: put message1 Maker: put message2 Maker: put message3 Maker: put message4 no space on the table. waiting for "put" Eater: take message1 Eater: take message2 Eater: take message3 no cake on the table. waiting for "put" Maker: put end Eater: take message4 Eater: take end
pic ファイル
.PS copy "sequence.pic"; boxwid = 1.3; # Define the objects object(M,":maker"); object(T,":table"); object(E,":eater"); step(); # Message sequences active(M); active(E); message(M,T,"put"); active(T); rmessage(T,M,""); inactive(T); message(M,T,"put"); active(T); rmessage(T,M,""); inactive(T); message(M,T,"put"); active(T); rmessage(T,M,""); inactive(T); message(M,T,"put"); active(T); comment(T,T2,up 0.5 right 0.2,wid 1.5 ht 0.5 "no space on the table." "waiting for \"take\"."); step(); message(E,T,"take"); active(T); rmessage(T,E,""); inactive(T); rmessage(T,M,""); inactive(T); message(E,T,"take"); active(T); rmessage(T,E,""); inactive(T); message(E,T,"take"); active(T); rmessage(T,E,""); inactive(T); message(E,T,"take"); active(T); rmessage(T,E,""); inactive(T); message(E,T,"take"); active(T); comment(T,T2,up 0.5 left 0.2,wid 1.5 ht 0.5 "no cake on the table." "waiting for \"put\"."); step(); message(M,T,"put"); active(T); rmessage(T,M,""); inactive(T); rmessage(T,E,""); inactive(T); complete(M); complete(T); complete(E); .PE
参考
増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編
増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編
- 作者: 結城浩
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2006/03/21
- メディア: 大型本
- 購入: 15人 クリック: 287回
- この商品を含むブログ (206件) を見る
Coro で Balking パターン
増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編 を参考に Coro で Balking パターンを実装。Balking パターン途中で止めること(Balkする=途中で止める)。この例だと「保存しようとしたけど、既に保存されていたらやめちゃおう。」
use strict; use warnings; package Changer; use Coro; use Coro::Timer; sub new { my ( $class, %args ) = @_; bless \%args, $class; } sub run { my $self = shift; my $coro = async { do { my $data = $self->{data}; my $text; $text = "data1"; print "Changer: change $text\n"; $data->change($text); print "Changer: save\n"; $data->save(); $text = "data2"; print "Changer: change $text\n"; $data->change($text); print "Changer: save\n"; $data->save(); $text = "data3"; print "Changer: change $text\n"; $data->change($text); print "Changer: sleep...\n"; Coro::Timer::sleep(2); print "Changer: save\n"; $data->save(); }; }; } package Saver; use Coro; use Coro::Timer; sub new { my ( $class, %args ) = @_; my %defaults = ( period => 3 ); %args = ( %defaults, %args ); bless \%args, $class; } sub run { my $self = shift; my $coro = async { do { my $period = $self->{period}; my $data = $self->{data}; while (1) { print "Saver : save\n"; $data->save(); Coro::Timer::sleep($period); } }; }; return $coro; } package Data; use Coro; use Coro::Semaphore; sub new { my ( $class, %args ) = @_; $args{sem} = Coro::Semaphore->new; $args{changed} = 0; bless \%args, $class; } sub change { my $self = shift; $self->{content} = shift; $self->{changed} = 1; } sub save { my $self = shift; my $guard = $self->{sem}->guard(); if ( $self->{changed} == 1 ) { print "Data : do_save\n"; $self->do_save(); $self->{changed} = 0; } else { print "Data : don't do_save and balk\n"; } } sub do_save { my $self = shift; my $file = $self->{file}; open my $fh, '>', $file or die "$!:$file"; print {$fh} $self->{content}; close $fh or die "$!:$file"; } package main; use Coro; my $data = Data->new( file => 'data.txt' ); my $saver = Saver->new( data => $data, period => 1 ); my $changer = Changer->new( data => $data ); my $changer_coro = $changer->run(); my $saver_coro = $saver->run(); $changer_coro->join(); $saver_coro->cancel();
出力
$ perl -w Balking.pl Changer: change data1 Changer: save Data : do_save Changer: change data2 Changer: save Data : do_save Changer: change data3 Changer: sleep... Saver : save Data : do_save Saver : save Data : don't do_save and balk Changer: save Data : don't do_save and balk Saver : save Data : don't do_save and balk
pic ファイル
.PS copy "sequence.pic"; boxwid = 1.3; # Define the objects object(C,":changer"); object(D,":data"); object(S,":saver"); step(); # Message sequences active(C); active(S); comment(S,T2,down 0.25 right 0.25,wid 1.25 ht 0.25 "save periodically"); message(C,D,"change"); active(D); rmessage(D,C,""); inactive(D); message(C,D,"save"); active(D); message(D,D,"do_save"); active(D); step(); inactive(D); rmessage(D,C,""); inactive(D); message(C,D,"change"); active(D); rmessage(D,C,""); inactive(D); message(S,D,"save"); active(D); message(D,D,"do_save"); active(D); step(); inactive(D); rmessage(D,S,""); inactive(D); message(C,D,"save"); active(D); comment(D,T2,up 0.5 left 0.5,wid 1 ht 0.5 "don't do_save," "and balk"); rmessage(D,C,""); inactive(D); complete(C); complete(D); complete(S); .PE
参考
増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編
増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編
- 作者: 結城浩
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2006/03/21
- メディア: 大型本
- 購入: 15人 クリック: 287回
- この商品を含むブログ (206件) を見る
Coro で Guarded-Suspension パターン (Coro::Signal使用)
増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編 の Guarded-Suspension パターンを Coro で実装。前回は Coro::Channelを使ったが、Coro::Channelを使うとキューが一杯になると、ブロックしてしまう。
use strict; use warnings; use Coro; use Coro::Channel; my $max = 2; my $ch = Coro::Channel->new($max); my $put_coro = async { do { for my $count ( 1 .. 10 ) { print "send $count\n"; $ch->put($count); } }; }; my $get_coro = async { do { while (1) { my $count = $ch->get; print "recv $count\n"; } }; }; $put_coro->join(); $get_coro->cancel();
上のスクリプトを実行すると、2 つメッセージを送ると送信側がブロックするのがわかる。
send 1 send 2 recv 1 recv 2 send 3 send 4 recv 3 recv 4 send 5 send 6 recv 5 recv 6 send 7 send 8 recv 7 recv 8 send 9 send 10 recv 9 recv 10
そこで、書籍のとおりにシグナル (この例では Coro::Signal) を使って Guarded-Suspension パターンを実装する。キューが一杯になると破棄している。
use strict; use warnings; package Client; use Coro; use Coro::Timer; sub new { my ( $class, %args ) = @_; bless \%args, $class; } sub run { my $self = shift; my $coro = async { do { my $queue = $self->{queue}; my $msg; $msg = "message1"; print "Client: put $msg\n"; $queue->put($msg); $msg = "message2"; print "Client: put $msg\n"; $queue->put($msg); print "Client: sleep...\n"; Coro::Timer::sleep(1); $msg = "end"; print "Client: put $msg\n"; $queue->put($msg); }; }; return $coro; } package Server; use Coro; sub new { my ( $class, %args ) = @_; bless \%args, $class; } sub run { my $self = shift; my $coro = async { do { my $queue = $self->{queue}; while (1) { my $msg = $queue->get; print "Server: get $msg\n"; last if $msg =~ m/^end$/; } }; }; return $coro; } package Queue; use Coro; use Coro::Semaphore; use Coro::Signal; sub new { my ( $class, %args ) = @_; my %defaults = ( max => 3 ); %args = ( %defaults, %args ); $args{signal} = Coro::Signal->new; $args{queue} = []; $args{put_sem} = Coro::Semaphore->new; $args{get_sem} = Coro::Semaphore->new; bless \%args, $class; } sub put { my $self = shift; my $guard = $self->{put_sem}->guard(); if ($self->{max} <= scalar( @{ $self->{queue} } )) { warn "no space in queue"; return; } push @{ $self->{queue} }, $_[0]; $self->{signal}->broadcast(); } sub get { my $self = shift; my $guard = $self->{get_sem}->guard(); while ( scalar( @{ $self->{queue} } ) == 0 ) { $self->{signal}->wait(); } return shift @{ $self->{queue} }; } package main; use Coro; my $queue = Queue->new( max => 5 ); my $server = Server->new( queue => $queue ); my $client = Client->new( queue => $queue ); my $client_coro = $client->run(); my $server_coro = $server->run(); $client_coro->join(); $server_coro->join();
出力
Client: put message1 Client: put message2 Client: sleep... Server: get message1 Server: get message2 Client: put end Server: get end
参考
増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編
増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編
- 作者: 結城浩
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2006/03/21
- メディア: 大型本
- 購入: 15人 クリック: 287回
- この商品を含むブログ (206件) を見る
Coro で Guarded-Suspension パターン (Coro::Channel使用)
増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編 の Guarded-Suspension パターンを Coro で実装。Guarded-Suspension パターンは要するにメッセージ送受信。Coro::Channel を使ったが、 Coro::Channel を使うと厳密には、Producer-Consumer パターンになるっぽい。
use strict; use warnings; package Client; use Coro; use Coro::Timer; sub new { my ( $class, %args ) = @_; bless \%args, $class; } sub run { my $self = shift; my $coro = async { do { my $ch = $self->{channel}; my $msg; $msg = "message1"; print "Client: put $msg\n"; $ch->put($msg); $msg = "message2"; print "Client: put $msg\n"; $ch->put($msg); print "Client: sleep...\n"; Coro::Timer::sleep(1); $msg = "end"; print "Client: put $msg\n"; $ch->put($msg); }; }; return $coro; } package Server; use Coro; sub new { my ( $class, %args ) = @_; bless \%args, $class; } sub run { my $self = shift; my $coro = async { do { my $ch = $self->{channel}; while (1) { my $msg = $ch->get; print "Server: get $msg\n"; last if $msg =~ m/^end$/; } }; }; return $coro; } package main; use Coro; use Coro::Channel; my $channel = Coro::Channel->new; my $server = Server->new( channel => $channel ); my $client = Client->new( channel => $channel ); my $client_coro = $client->run(); my $server_coro = $server->run(); $client_coro->join(); $server_coro->join();
結果出力
Client: put message1 Client: put message2 Client: sleep... Server: get message1 Server: get message2 Client: put end Server: get end
pic ファイル
.PS copy "sequence.pic"; boxwid = 1.3; # Define the objects object(CL,":client"); object(CH,":channel"); object(S,":server"); step(); # Message sequences active(CL); active(S); message(CL,CH,"put"); active(CH); rmessage(CH,CL,""); inactive(CH); message(CL,CH,"put"); active(CH); rmessage(CH,CL,""); inactive(CH); message(S,CH,"get"); active(CH); rmessage(CH,S,""); inactive(CH); message(S,CH,"get"); active(CH); rmessage(CH,S,""); inactive(CH); message(S,CH,"get"); active(CH); comment(CH,T2,up 0.5 left 0.5,wid 1 ht 0.5 "waiting for" "put"); message(CL,CH,"put"); active(CH); rmessage(CH,CL,""); inactive(CH); rmessage(CH,S,""); inactive(CH); complete(CL); complete(CH); complete(S); .PE
参考
増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編
増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編
- 作者: 結城浩
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2006/03/21
- メディア: 大型本
- 購入: 15人 クリック: 287回
- この商品を含むブログ (206件) を見る
GNU PIC の出力画像を綺麗にする
GNU PIC の出力画像が綺麗でないことが不満だったが、一旦SVGファイルにしてから、png などの画像にすれば綺麗になることがわかった。
SVG に直してから変換した画像出力。
今までのスクリプト
pic2plot コマンドで ppm ファイルにして、余計な余白を削除している。
#!/bin/sh PIC_FILE=$1 if [ ! -f "$PIC_FILE" ]; then echo "Usage : "`basename $0`" pic_file [gif_file]" exit 1 fi if [ $# -eq 2 ] then GIF_FILE=$2 else GIF_FILE=`echo $PIC_FILE | sed 's/[^.]*$/gif/'` fi perl -pe 's/\x0D\x0A|\x0D/\x0A/g' $PIC_FILE | \ iconv -t EUC-JP | \ pic2plot -T pnm -F HersheyEUC --bitmap-size '1024x1024' |\ pnmcrop |\ (ppmtogif 2> /dev/null) > $GIF_FILE
改良したスクリプト
pic2plot コマンドの出力を SVG にしてから、 ppm -> 最終画像 に変換するようにした(ついでに、 gif から png に変更)。一番のポイントは rsvg-convert を使って画像変換するようにしたこと。
#!/bin/sh PIC_FILE=$1 if [ ! -f "$PIC_FILE" ]; then echo "Usage : "`basename $0`" pic_file [png_file]" exit 1 fi if [ $# -eq 2 ] then PNG_FILE=$2 else PNG_FILE=`echo $PIC_FILE | sed 's/[^.]*$/png/'` fi case "$OS" in Windows* ) # for cygwin FONT='Arial-Roman' PNG2PPM='pngtopam' ;; *) FONT='Helvetica' PNG2PPM='pngtopnm' ;; esac perl -pe 's/\x0D\x0A|\x0D/\x0A/g' $PIC_FILE | \ iconv -t EUC-JP | \ pic2plot -T svg -F $FONT --bitmap-size '1024x1024' | \ rsvg-convert -f png | $PNG2PPM | pnmcrop | pnmtopng > $PNG_FILE
PIC ファイル
.PS ellipse "document"; arrow; box width 0.6 "\fIpic\fP(1)" arrow; box width 1.1 "\fIgtbl\fP(1) or \fIgeqn\fP(1)" "(optional)" dashed; arrow; box width 0.6 "\fIgtroff\fP(1)"; arrow; ellipse "PostScript" .PE
Streaming API で XMLの読み出し
Libxml2 の Streaming API っていうのは、 XML を頭から解析するときに役立つ API。SAXと違ってハンドラを登録する必要がないから楽。
#include <stdio.h> #include <libxml/tree.h> #include <libxml/xmlreader.h> void processNode(xmlTextReaderPtr reader) { const xmlChar *name; const xmlChar *value; int ret; /* Print node infos */ name = xmlTextReaderConstName(reader); if (NULL == name) { name = BAD_CAST "--"; } printf("%d %d %s %d %d %d, ", xmlTextReaderDepth(reader), xmlTextReaderNodeType(reader), name, xmlTextReaderIsEmptyElement(reader), xmlTextReaderHasValue(reader), xmlTextReaderHasAttributes(reader)); /* Print value */ if (1 == xmlTextReaderHasValue(reader)) { printf("value: "); value = xmlTextReaderConstValue(reader); if (value == NULL) { printf("--, "); } else { if (xmlStrlen(value) > 40) { printf("%.40s..., ", value); } else { printf("%s,", value); } } } /* Print attribute */ if (1 == xmlTextReaderHasAttributes(reader)) { printf("attr: "); ret = xmlTextReaderMoveToFirstAttribute(reader); while(1 == ret) { printf("%s = %s, ", xmlTextReaderConstName(reader), xmlTextReaderConstValue(reader)); ret = xmlTextReaderMoveToNextAttribute(reader); } } printf("\n"); } int main(int argc, char **argv) { xmlTextReaderPtr reader; char *input_file; int ret; if (argc != 2) { return 1; } input_file = argv[1]; LIBXML_TEST_VERSION; /* Read document */ reader = xmlReaderForFile(input_file, NULL, 0); if (NULL == reader) { fprintf(stderr, "Failed to parse %s\n", input_file); return; } /* Parse XML */ while (1 == (ret = xmlTextReaderRead(reader))) { processNode(reader); } if (0 != ret) { fprintf(stderr, "%s : failed to parse\n", input_file); } /* Free reader */ xmlFreeTextReader(reader); xmlCleanupParser(); return 0; }
解析対象 XML。
<?xml version="1.0" encoding="UTF-8" ?> <cars> <car country="US" type="car"> <price>150</price> <img file="car1.jpg"/> </car> <car country="JP" type="truck"> <price>500</price> <img file="car2.jpg"/> </car> </cars>
上のXMLを解析すると出力は次のようになる。
0 1 cars 0 0 0, 1 14 #text 0 1 0, value: , 1 1 car 0 0 1, attr: country = US, type = car, 2 14 #text 0 1 0, value: , 2 1 price 0 0 0, 3 3 #text 0 1 0, value: 150, 2 15 price 0 0 0, 2 14 #text 0 1 0, value: , 2 1 img 1 0 1, attr: file = car1.jpg, 2 14 #text 0 1 0, value: , 1 15 car 0 0 1, attr: country = US, type = car, 1 14 #text 0 1 0, value: , 1 1 car 0 0 1, attr: country = JP, type = truck, 2 14 #text 0 1 0, value: , 2 1 price 0 0 0, 3 3 #text 0 1 0, value: 500, 2 15 price 0 0 0, 2 14 #text 0 1 0, value: , 2 1 img 1 0 1, attr: file = car2.jpg, 2 14 #text 0 1 0, value: , 1 15 car 0 0 1, attr: country = JP, type = truck, 1 14 #text 0 1 0, value: , 0 15 cars 0 0 0,
参考
The XML C parser and toolkit of Gnome
xmlReader Examples
やさしいXML 第3版
- 作者: 高橋麻奈
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2009/04/21
- メディア: 単行本
- 購入: 1人 クリック: 101回
- この商品を含むブログ (15件) を見る
Writing API で XMLの書き出し
Libxml2 の Writing API っていうのは、 XML を頭から出力するときに役立つ API。
#include <stdio.h> #include <string.h> #include <libxml/encoding.h> #include <libxml/xmlwriter.h> #define MY_ENCODING "UTF-8" /*****************************************************************************************/ /* output */ /* ------ */ /* <?xml version="1.0" encoding="UTF-8"?> : xmlTextWriterStartDocument & */ /* : xmlTextWriterWriteAttribute */ /* <EXAMPLE> : xmlTextWriterStartElement */ /* <!--This is a comment--> : xmlTextWriterWriteComment */ /* <ORDER version="1.0" xml:lang="de"> : xmlTextWriterStartElement & */ /* : xmlTextWriterWriteAttribute */ /* <!--This is formatted comment--> : xmlTextWriterWriteFormatComment */ /* <ENTRY> : xmlTextWriterStartElement */ /* <ARTICLE><Test></ARTICLE> : xmlTextWriterWriteElement */ /* <ENTRY_NO>Formatted Element 0010/ENTRY_NO> : xmlTextWriterWriteFormatElement */ /* </ENTRY> : xmlTextWriterEndElement */ /* <FOOT>Formatted string 1</FOOT> : xmlTextWriterStartElement & */ /* : xmlTextWriterWriteFormatString & */ /* : xmlTextWriterEndElement */ /* </ORDER> : xmlTextWriterEndDocument */ /* </EXAMPLE> : */ /*****************************************************************************************/ void testXmlwriterFilename(const char *uri) { int ret; xmlTextWriterPtr writer; /* Create a new XmlWriter for uri, with no compression. */ writer = xmlNewTextWriterFilename(uri, 0); if (writer == NULL) { fprintf(stderr, "Error creating the xml writer\n"); goto LAST; } /* Start the document with the xml default for the version, * encoding MY_ENCODING and the default for the standalone * declaration. */ ret = xmlTextWriterStartDocument(writer, NULL, MY_ENCODING, NULL); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterStartDocument\n"); goto LAST; } /* Start an element named "EXAMPLE". Since thist is the first * element, this will be the root element of the document. */ ret = xmlTextWriterStartElement(writer, BAD_CAST "EXAMPLE"); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterStartElement\n"); goto LAST; } /* Write a comment as child of EXAMPLE */ ret = xmlTextWriterWriteComment(writer, "This is a comment"); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterWriteComment\n"); goto LAST; } /* Start an element named "ORDER" as child of EXAMPLE. */ ret = xmlTextWriterStartElement(writer, BAD_CAST "ORDER"); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterStartElement\n"); goto LAST; } /* Add an attribute with name "version" and value "1.0" to ORDER. */ ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "1.0"); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterWriteAttribute\n"); goto LAST; } /* Add an attribute with name "xml:lang" and value "de" to ORDER. */ ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang", BAD_CAST "de"); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterWriteAttribute\n"); goto LAST; } /* Write a comment as child of ORDER */ ret = xmlTextWriterWriteFormatComment(writer, "This is formatted comment", "%d", 1); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterWriteFormatComment\n"); goto LAST; } /* Start an element named "ENTRY" */ ret = xmlTextWriterStartElement(writer, BAD_CAST "ENTRY"); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterStartElement\n"); goto LAST; } /* Write an element named "ARTICLE" as child of ENTRY. */ ret = xmlTextWriterWriteElement(writer, BAD_CAST "ARTICLE", BAD_CAST "<Test>"); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterWriteElement\n"); goto LAST; } /* Write an element named "ENTRY_NO" as child of ENTRY. */ ret = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ENTRY_NO", "Formatted element %04d", 10); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterWriteFormatElement\n"); goto LAST; } /* Close the element named ENTRY. */ ret = xmlTextWriterEndElement(writer); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterEndElement\n"); goto LAST; } /* Start an element named "FOOT" */ ret = xmlTextWriterStartElement(writer, BAD_CAST "FOOT"); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterStartElement\n"); goto LAST; } /* Write Text */ ret = xmlTextWriterWriteFormatString(writer, "Formatted string %d", 1); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterWriteFormatString\n"); goto LAST; } /* Close the element named FOOT. */ ret = xmlTextWriterEndElement(writer); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterEndElement\n"); goto LAST; } /* Here we could close the elements ORDER and EXAMPLE using the * function xmlTextWriterEndElement */ ret = xmlTextWriterEndDocument(writer); if (ret < 0) { fprintf(stderr, "Error at xmlTextWriterEndDocument\n"); goto LAST; } LAST: xmlFreeTextWriter(writer); } int main(int argc, char **argv) { char *output_file; int ret; if (argc != 2) { return 1; } output_file = argv[1]; LIBXML_TEST_VERSION; testXmlwriterFilename(output_file); xmlCleanupParser(); return; }
出力ファイル。素の状態だと見づらいので、xmllint --formatの出力。
<?xml version="1.0" encoding="UTF-8"?> <EXAMPLE> <!--This is a comment--> <ORDER version="1.0" xml:lang="de"> <!--This is formatted comment--> <ENTRY> <ARTICLE><Test></ARTICLE> <ENTRY_NO>Formatted element 0010</ENTRY_NO> </ENTRY> <FOOT>Formatted string 1</FOOT> </ORDER> </EXAMPLE>
参考
The XML C parser and toolkit of Gnome
xmlWriter Examples
やさしいXML 第3版
- 作者: 高橋麻奈
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2009/04/21
- メディア: 単行本
- 購入: 1人 クリック: 101回
- この商品を含むブログ (15件) を見る