こんにちは、デジタル事業本部の藤田です。
InDesign には XML を読み込んでドキュメントを作成する機能があります。XML を活用すると InDesign での自動組版だけでなく Web ページやデータベースとの連動を想定したクロスメディア展開が可能です。
目次
● XML とは
XML とは、eXtensible Markup Language(拡張マークアップ言語)の略で、タグ付けされた構造の情報です。1998年に W3C によって仕様が策定・勧告されました。
上記の画像では省略していますがユーザーごとに <名前> や <会社名> などの要素がぶらさがっています。
<?xml version="1.0" encoding="UTF-8"?> <名刺管理> <ユーザー> <名前>藤田 徳朗</名前> <name>Noriaki Fujita</name> <会社名>タクトシステム株式会社</会社名> <部署名>クロスメディアビジネス室</部署名> <URL>https://www.tactsystem.co.jp/</URL> <郵便番号>〒169-0051</郵便番号> <住所>東京都新宿区西早稲田3-27-1</住所> <電話>03-3200-0490</電話> <ロゴ画像 href="file://./tactロゴ.ai" /> </ユーザー> </名刺管理>
上記のサンプル XML ではルート(根)に <名刺管理> 要素が設定され、<名刺管理> の子ノードに <ユーザー> 要素、<ユーザー> 要素の子ノードに <名前> や <会社名> などの要素がぶらさがっている構造となります。<ロゴ画像> という要素には href 属性に画像ファイルのファイルパスが設定されています。
このようにタグで構造化されたデータを XML といいます。
● InDesign に XML を配置する
では InDesign にこの XML を配置してみます。詳細は Adobe のヘルプをご覧になった方がよく分かると思いますので、ここでは InDesign テンプレートに上記のサンプル XML を配置して名刺ファイルを作成する手順を紹介します。
用意するもの
・InDesign ファイル
・XML ファイル
・配置する画像(.ai ファイル)
InDesign でページアイテムに構造タグを割り当てる
下図のようにタグパレットで新規タグを作成し各テキストフレーム 、画像フレームに割り当てます。タグの名前は配置する XML ファイルで使用されているタグ要素と同じ名前です。また、タグは同名の段落スタイルとマッピングされています。
XML を読み込み
InDesign で「ファイルメニュー > XML を読み込み…」を選択します。
XML ファイルを選択するダイアログがあらわれるので配置する XML ファイルを選択します。このとき、画像ファイル(ここでいう「tactロゴ.ai」)は XML ファイルと同じ階下に置いておきます。「XML 読み込みオプションを表示」チェックボックスはオンに、「内容を結合」ラジオボタンをオンにして「開く」ボタンを押します。
「XML 読み込みオプション」の「モード:」プルダウンは「内容を結合」を選択し、チェックボックスはすべてオフにして「OK」ボタンを押します。
InDesign にタグの値が反映される
すると、InDesign にタグを割り当てた各テキストフレームにそれぞれのタグの値が入りました! 画像フレームには href 属性で設定したファイルパスの画像が配置されます。
オーバープリントプレビューにしてみます。
XML ファイルをリンク配置する
さらに、InDesign では XML ファイルをリンク配置することもできます。InDesign で「ファイルメニュー > XML を読み込み…」より配置する XML ファイルを選択、「XML 読み込みオプション」で「リンクを作成」チェックボックスをオンにして「OK」ボタンを押します。
InDesign に XML ファイルが配置された状態で XML ファイルのタグの値を書き換えます。
リンクパレットでは配置された XML ファイルのステータスが⚠️となります。このリンクを更新すると…
XML ファイルで値を書き換えたタグと同じ名前で割り当てられたテキストフレームの値も更新されました!
このように InDesign の構造タグに XML ファイルのタグを割り当てることでサンプルのようなドキュメントが作成できます。このサンプルのように単一ファイルでコマとして作成してあとでまとめて台紙に貼り付けたり、または複数ページに配置されたコマテキストフレームにあらかじめ構造タグを割り当てておけば XML ファイルを配置するだけでドキュメントが仕上がります。さらに XML ファイルをリンク配置すれば値を書き換えるだけで同じフォーマットのドキュメントを作成することも可能です。
これら XML ファイルの配置やリンク更新をスクリプトでコントロールすれば自動組版ソリューションも構築できます。
● グラフィックセルを含む表組に XML を配置する
InDesign には CC 2015 よりグラフィックセルという機能が搭載されました。
上の名刺サンプルではテキストフレームおよび画像フレームに構造タグを割り当てていましたが表組およびセル、グラフィックセルにも構造タグを割り当てることが可能です。
表組に構造タグを割り当てる
下図のようにドキュメントのルート(根)に構造タグ <Root> が、テキストフレームに構造タグ <ストーリー> が、そしてテキストフレーム内の表組に構造タグ <名刺管理> が割り当てられており、表の各セルにも構造タグが割り当てられています。1行目の各セルは構造タグ <ヘッダー> が、2行目以降の各セルには構造タグ <セル> が、2行目以降最終列のグラフィックセルには構造タグ <画像ロゴ> が割り当てられています。
配置する XML ファイル
<?xml version="1.0" encoding="utf-8" ?> <Root><ストーリー><名刺管理><ヘッダー>名前</ヘッダー><ヘッダー>name</ヘッダー><ヘッダー>会社名</ヘッダー><ヘッダー>部署名</ヘッダー><ヘッダー>URL</ヘッダー><ヘッダー>郵便番号</ヘッダー><ヘッダー>住所</ヘッダー><ヘッダー>電話</ヘッダー><ヘッダー>ロゴ画像</ヘッダー><セル>藤田 徳朗</セル><セル>Noriaki Fujita</セル><セル>タクトシステム株式会社</セル><セル>クロスメディアビジネス室</セル><セル>https://www.tactsystem.co.jp/</セル><セル>〒169-0051</セル><セル>東京都新宿区西早稲田3-27-1</セル><セル>03-3200-0490</セル><セル><ロゴ画像 href="file://./tactロゴ.ai" /></セル></名刺管理></ストーリー></Root>
配置される InDesign ドキュメントと対応した構造のタグとなっています。タグの要素には格納する値が設定されており、タグ <ロゴ画像> の要素には href 属性に画像ファイルのファイルパスが設定されています。タグ <名刺管理> の中にはタグ <ヘッダー> <セル> があり、さらにグラフィックセルに対応するタグ <セル> の中には <ロゴ画像> タグがあります。タグとタグの間に改行は入れないことがポイントです。
XML 読み込みオプション
「XML 読み込みオプション」は「タグが一致した場合テキスト要素を表に読み込む」チェックボックスをオンにして「OK」ボタンを押します。
表組に XML ファイルが配置される
すると、グラフィックセルを含む表組に XML ファイルが配置されました!
オーバープリントプレビューにしてみます。
● XML をXSLT に通して HTML に変換
XML を XSLT に通すことでデータ形式を変換することも可能です。XSLT(XSL Transformations)とは XML の変換スタイルシートのことで XML と同様 W3C によって仕様を策定・勧告された言語です。XML を CSV や HTML、また別の構造を持った XML に変換することができます。今回は XML を HTML に変換してみます。
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/"> <html lang="ja"> <head><meta charSet="utf-8"/></head> <body> <table border="1"> <tr> <th>タグ</th> <th>値</th> </tr> <xsl:for-each select="名刺管理/ユーザー/*"> <tr> <td> <xsl:value-of select="name()" /> </td> <td> <xsl:choose> <xsl:when test="name()='URL'"> <xsl:call-template name="URL"/> </xsl:when> <xsl:when test="name()='ロゴ画像'"> <xsl:call-template name="logo"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="." /> </xsl:otherwise> </xsl:choose> </td> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> <xsl:template name="URL"> <a> <xsl:attribute name="href"> <xsl:value-of select="."/> </xsl:attribute> <xsl:value-of select="."/> </a> </xsl:template> <xsl:template name="logo"> <img> <xsl:attribute name="src">tactlogo.png</xsl:attribute> </img> </xsl:template> </xsl:stylesheet>
上記の XSLT ファイルを XML ファイルと同じ階層に置いて xsltproc コマンドで変換すると HTML が作成されます。この記事最初のサンプル XML ファイルを「xml_sample.xml」、XSLT ファイルを「html.xsl」という名前でそれぞれ保存し「tactlogo.png」という名前の画像を同階層に置いて下記の xsltproc コマンドを実行すると「output.html」が作成されます。
xsltproc -o "output.html" "html.xsl" "xml_sample.xml"
xsltproc は XSLT を実行するコマンドで、macOS ではターミナル(標準でインストール済み)より、Windows ではコマンドプロンプト(インストールが必要)より実行できます。
この仕組みを応用すればひとつの XML ファイルで Web と InDesign を作成するといったワンソースマルチユースな展開も可能です。
とはいえ XSLT はちょっと古い技術である感は否めず、最近はいろんな言語で XML のパースもあっさりできちゃいますのであまり積極的に使用する類の技術ではないと思います。
InDesign の XML 読み込みオプションには「XSLT を適用:」というチェックボックスがあるので既存の XML を 変換して InDesign に配置する必要がある場合は XSLT が有用です。
● 補足:CSV(Excel) から XML ファイルへ書き出す技術
CSV(Excel) から XML ファイルへ書き出す方法をいろいろな言語で書いてみました。
いずれも CSV の1行目をキーにして行ごとに <ユーザー> で構造化しています。ルートは <名刺管理> です。XML 宣言とルートではじまる要素だけで <ロゴ画像> 以外は属性を持たないシンプルな整形式 XML です。
AppleScript
property LF : ASCII character 10 property CR : ASCII character 13 property comma : ASCII character 44 property solidus : ASCII character 47 property less_than_sign : ASCII character 60 property greater_than_sign : ASCII character 62 property rootName : "名刺管理" property rootChiledName : "ユーザー" property xmlFileName : "名刺管理.xml" set csvFile to choose file of type {"public.comma-separated-values-text"} set readStreamList to read csvFile using delimiter {CR, LF, CR & LF} as «class utf8» set saveDelimiter to AppleScript's text item delimiters set AppleScript's text item delimiters to comma set a2dList to {} repeat with readStream in readStreamList if (count of readStream) is not 0 then set end of a2dList to every text item of readStream end repeat set AppleScript's text item delimiters to saveDelimiter set keyList to first item of a2dList set value2DList to rest of a2dList set xmlString to "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" set xmlString to xmlString & LF & less_than_sign & rootName & greater_than_sign repeat with i from 1 to count of value2DList set xmlString to xmlString & LF & less_than_sign & rootChiledName & greater_than_sign set valueList to item i of value2DList repeat with n from 1 to count of valueList set |key| to item n of keyList set value to item n of valueList if value starts with "file://" then set tagString to less_than_sign & |key| & " href=\"" & value & "\" /" & greater_than_sign else set tagString to less_than_sign & |key| & greater_than_sign & value & less_than_sign & solidus & |key| & greater_than_sign end if set xmlString to xmlString & LF & tagString end repeat set xmlString to xmlString & LF & less_than_sign & solidus & rootChiledName & greater_than_sign end repeat set xmlString to xmlString & LF & less_than_sign & solidus & rootName & greater_than_sign set writeFile to choose file name default name xmlFileName try set writeStream to open for access writeFile with write permission set eof writeStream to 0 write xmlString to writeStream as «class utf8» end try close access writeStream return xmlString
スクリプトエディタで実行すると CSV ファイルを選択するダイアログがあらわれるのでファイルを選択すると XML ファイルが書き出される仕組みとなっています。AppleScript 単体では XML は書き出せないので読み込んだ CSV ファイルを改行で区切りカンマごとのテキストを山カッコ(< >)で囲んで XML を組み立てるという力技です。テキストが file://〜 で始まる場合は href 属性として取り込みます。AppleScriptObjC(Objective-C)であれば NSPropertyListXMLFormat_v1_0 で XML の構造化は可能ですがこちらの方法は設定を保存するプロパティリストを作成するためのものなので今回は取り上げませんでした。
VBA
Sub csvtoxml() Dim rows, cols As Long With ActiveSheet.usedRange rows = .rows.Count cols = .Columns.Count End With Dim Table As Variant Table = ActiveSheet.usedRange Dim LF, solidus, less_than_sign, greater_than_sign, xmlString, rootName, rootChiledName As String LF = Chr(10) solidus = Chr(47) less_than_sign = Chr(60) greater_than_sign = Chr(62) xmlString = "<?xml version=""1.0"" encoding=""UTF-8""?>" rootName = "名刺管理" rootChiledName = "ユーザー" xmlString = xmlString & LF & less_than_sign & rootName & greater_than_sign Dim i, n As Long Dim key, value, tagString As String For i = 2 To rows xmlString = xmlString & LF & less_than_sign & rootChiledName & greater_than_sign For n = 1 To cols key = Table(1, n) value = Table(i, n) If value Like "file://*" Then tagString = less_than_sign & key & " href=""" & value & """ / " & greater_than_sign Else tagString = less_than_sign & key & greater_than_sign & value & less_than_sign & solidus & key & greater_than_sign End If xmlString = xmlString & LF & tagString Next n xmlString = xmlString & LF & less_than_sign & solidus & rootChiledName & greater_than_sign Next i xmlString = xmlString & LF & less_than_sign & solidus & rootName & greater_than_sign Dim sp, writeFile As String writeFile = Application.GetSaveAsFilename(InitialFileName:="名刺管理.xml") If writeFile <> "False" Then Dim adostBOM, adostNoBOM As Object Set adostBOM = CreateObject("ADODB.Stream") Set adostNoBOM = CreateObject("ADODB.Stream") With adostBOM .Charset = "UTF-8" .Open .WriteText xmlString .Position = 3 End With With adostNoBOM .Type = 1 .Open End With With adostBOM .CopyTo adostNoBOM .Close End With With adostNoBOM .SaveToFile writeFile, 2 .Close End With End If End Sub
こちらは Excel 上でマクロを書きました。Excel で1行目に項目名、2行目以降に値を入れておきマクロを実行すると XML ファイルが書き出されます。こちらもセルの値を山カッコで囲んで XML を組み立てる点では文法が違うだけでアプローチは上記の AppleScript とほとんど同じです。VBA では XmlMap というオブジェクトから XML をエクスポートできますがスキーマが必要で難易度がやや高いため上記の方法にしました。BOM なし UTF-8 で書き出すために ADO(ActiveX Data Objects)を実行時にバインディングしています。そのため Windows 版 Excel でしか動作しません。
Python
# -*- coding: utf-8 -*- import pandas as pd import xml.etree.ElementTree as et csvFile = r"address.csv" xmlFile = r"名刺管理.xml" nameKey = "名前" nameKey_ = "name" companyKey = "会社名" departmentKey = "部署名" urlKey = "URL" postCodeKey = "郵便番号" addressKey = "住所" telKey = "電話" logoFileKey = "ロゴ画像" df = pd.read_csv(csvFile) root = et.Element("名刺管理") for i, row in df.iterrows(): rootChiled = et.SubElement(root, "ユーザー") name = et.SubElement(rootChiled, nameKey) name_ = et.SubElement(rootChiled, nameKey_) company = et.SubElement(rootChiled, companyKey) department = et.SubElement(rootChiled, departmentKey) url = et.SubElement(rootChiled, urlKey) postCode = et.SubElement(rootChiled, postCodeKey) address = et.SubElement(rootChiled, addressKey) tel = et.SubElement(rootChiled, telKey) logoFile = et.SubElement(rootChiled, logoFileKey) for n, column in df.iteritems(): if n == nameKey: name.text = str(row[n]) elif n == nameKey_: name_.text = str(row[n]) elif n == companyKey: company.text = str(row[n]) elif n == departmentKey: department.text = str(row[n]) elif n == urlKey: url.text = str(row[n]) elif n == postCodeKey: postCode.text = str(row[n]) elif n == addressKey: address.text = str(row[n]) elif n == telKey: tel.text = str(row[n]) elif n == logoFileKey: logoFile.set("href", str(row[n])) et.ElementTree(root).write(xmlFile, encoding="utf-8", xml_declaration=True, method='xml', short_empty_elements=False)
Python では pandas ライブラリで CSV を読み込み、xml.etree.ElementTree モジュールを使って XML を書き出します。ライブラリが用意されているのは便利ではありますが、要素ごとに変数を作成して値を格納しなくてはいけないのがちょっと手間ですね。とはいえ CSV を XML に書き出す方法としては各言語の中では Python で書くのがいちばんスマートだと思いました。また、Python はコード内の入出力ファイルパス(csvFile と xmlFile)を適時書き換えれば macOS でも Windows でも動作します。上記の例のようにソースコードと同階層に入出力ファイルがあれば書き換えの必要はありません。
その他
その他 CSV から XML へ書き出す方法としては Google スプレッドシートから GAS を使用する方法、Excel の「名前をつけて保存」よりファイル形式「*.xml」を選択する方法などがあったのですが難易度がかなり高いため取り上げませんでした。そもそも行と列の表を木構造にすること自体無理があるので実務では XML データベースなどを使用するのが一般的かもしれません。
● 自動組版開発承ります
InDesign での XML の読み込みには今回紹介した方法以外にもタグマーカーの使用や属性値を取り込むなどさまざまな操作が可能です。柔軟性が高く奥が深い XML 組版ではありますがそれなりの前提知識が必要なのも事実です。タクトシステムではこういった自動組版開発のご相談内容に応じたご提案をさまざまな角度からいたします。
また、タクトシステム オープンエンド事業本部が提供するパッケージソフト MyAutoPub であれば InDesign XML 自動組版ソリューションをご自身で構築できます。XML が初めてでも大丈夫な、CSV→XMLナビ機能を搭載。InDesignの良さを引き出すXMLを生成します。
ご興味あればお気軽にお問い合わせください。