本投稿は Delphi AdventCalender 2023 #11 の記事です。
はじめに
TXMLDocumentを利用すると,Delphiで簡単にXMLが利用できます。XMLはヘッダでUTF-8を指定すれば日本語のエンコードを気にする必要がありません。また,WindowsだけでなくMacOSやLinuxでも利用できます。
LinuxではUTF-8はBOM(Byte Order Mark)無しで,改行はLF(#10)を使うのが一般的なのでそれに合わせた出力を求められることがありますが,TXMLDocumentだけではそれに対応することができませんでした。
そこで,TStringListと組み合わせてBOM無しLF改行のXMLを出力する方法に挑戦してみました。
SaveToFileで保存する
まずは,TXMLDocumentのSaveToFileを使います。Windows VCLアプリケーションを新規作成し,Button
とXMLDocument
をフォームに配置します。Button1
のOnClickイベントを追加し,以下のようにコードを書きます。
※ 保存するファイル名は保存できる場所に必ず書き換えてください。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Xml.xmldom, Xml.XMLIntf, Xml.XMLDoc,
Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
XMLDocument1: TXMLDocument;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
const
XML_Sample = // XMLのサンプルです
'<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>'+
'<test attr="sample">'+
' 日本語body'+
'</test>';
procedure TForm1.Button1Click(Sender: TObject); // Button1のOnClickイベント
var
lStrStream: TMemoryStream;
st:TStringList;
begin
XMLDocument1.XML.text := XML_sample; // XMLDocument1にサンプルを代入します
XMLDocument1.Active := True; // アクティブにしないと保存できないです
XMLDocument1.SaveToFile('sample.xml'); // ファイル名は適切な場所に変更してください
end;
end.
プログラムを実行してButton1をクリックすると,sample.xmlが保存されます。
テキストエディタで開くと,このXMLがBOM無のCRLF改行のUTF-8で保存されていることが分かります。エンコードを指定しなくてもBOM無UTF-8で保存できることが分かりました。
TStringListを使う
しかし,改行をLFに変えたいのですが,TXMLDocumentに改行コードを変更する方法をみつけることができませんでした。そこで,TXMLDocumentの内容をTMemoryStreamでTStringListに渡して出力することにしました。TForm1.Button1Click
を以下のように書き換えます。
※ 保存するファイル名は保存できる場所に必ず書き換えてください。
procedure TForm1.Button1Click(Sender: TObject);
var
LMemoryStream: TMemoryStream;
st:TStringList;
begin
XMLDocument1.XML.text := XML_sample;
XMLDocument1.Active := True;
LMemoryStream:=TMemoryStream.Create;
XMLDocument1.SaveToStream(LMemoryStream);
LMemoryStream.Position:=0;
st:=TStringList.Create;
st.LoadFromStream(LMemoryStream,TEncoding.UTF8);
LMemoryStream.Free;
st.LineBreak := #10; // 改行をLF #10 にする
st.WriteBOM := False; // BOMを出力しない デフォルトはTrue
st.SaveToFile('sample2.xml',TEncoding.UTF8); // UTF-8で出力 ファイル名は適切な場所に変更してください
st.Free;
end;
MemoryStreamからデータを受け取るにはPosition := 0;
にしてから,LoadStream
でTEncoding.UTF8
でエンコードをUTF-8にする必要があります。
TStringList
は,デフォルトでBOMを出力しますので,WriteBOM:= False;
を指定する必要があります。
改行はLineBreak
で改行コードを指定します。
UTF-8で保存するためSaveToFile
でTEncoding.UTF8
を指定しています。
実行してButton1をクリックするとXMLファイルが出力されます。テキストエディタで開くと,UTF-8でBOM無しLF改行のXMLファイルであることが確認できます。
おまけ1: 行末の改行の設定を変更する
TStringListで保存されたファイルの最後(EOF)の前は改行ですが,改行をつけたくない場合もあるかもしれません。
その時には以下のようにTrailingLineBreak
プロパティを指定すると可能です。
st.TrailingLineBreak := False;
おまけ2: 複数行の文字列(Delphi12以降)
Delphi 12から,複数行の文字列を簡単に記述できるようになりました。XML_sample定数は以下のように書くことができます。
XML_Sample = '''
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<test attr="sample">
日本語body
</test>
''';
Qiitaはもう対応しているんですね。
まとめ
TMXLDocument
の出力をBOM無しLF改行でUTF-8で出力するには,TMemoryStream
を介してTStringList
を使い,WriteBOM
プロパティやLineBreak
プロパティを指定すると出力できることが分かりました。
この情報が皆様のお役に立てば幸いです。間違いがございましたらお知らせください。