HAKADORI その他

InDesign で自動組版【XML編】

2020.12.25 金

こんにちは、CMB室の藤田です。

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 を配置するために用意するもの

InDesign でページアイテムに構造タグを割り当てる

下図のようにタグパレットで新規タグを作成し各テキストフレーム 、画像フレームに割り当てます。タグの名前は配置する XML ファイルで使用されているタグ要素と同じ名前です。また、タグは同名の段落スタイルとマッピングされています。

InDesign でページアイテムに構造タグを割り当てる

InDesign でページアイテムに構造タグを割り当てる

XML を読み込み

InDesign で「ファイルメニュー > XML を読み込み…」を選択します。
InDesign で XML を読み込み
XML ファイルを選択するダイアログがあらわれるので配置する XML ファイルを選択します。このとき、画像ファイル(ここでいう「tactロゴ.ai」)は XML ファイルと同じ階下に置いておきます。「XML 読み込みオプションを表示」チェックボックスはオンに、「内容を結合」ラジオボタンをオンにして「開く」ボタンを押します。

XML を読み込みダイアログ

XML を読み込み

「XML 読み込みオプション」の「モード:」プルダウンは「内容を結合」を選択し、チェックボックスはすべてオフにして「OK」ボタンを押します。

XML 読み込みオプション

XML 読み込みオプション

InDesign にタグの値が反映される

すると、InDesign にタグを割り当てた各テキストフレームにそれぞれのタグの値が入りました! 画像フレームには href 属性で設定したファイルパスの画像が配置されます。

InDesign にタグの値が反映される

InDesign にタグの値が反映される

オーバープリントプレビューにしてみます。

オーバプリントプレビューにしたところ

オーバープリントプレビューにしたところ

 

XML ファイルをリンク配置する

さらに、InDesign では XML ファイルをリンク配置することもできます。InDesign で「ファイルメニュー > XML を読み込み…」より配置する XML ファイルを選択、「XML 読み込みオプション」で「リンクを作成」チェックボックスをオンにして「OK」ボタンを押します。

「リンクを作成」チェックボックスをオン

「リンクを作成」チェックボックスをオン

InDesign に XML ファイルが配置された状態で XML ファイルのタグの値を書き換えます。

「名前」「name」「部署名」の値を書き換え

<名前><name><部署名>の値を書き換え

リンクパレットでは配置された 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 ファイルが配置される

表組に 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 を XSLT で変換して作成された HTML ファイル

XML を XSLT で変換して作成された HTML ファイル

この仕組みを応用すればひとつの 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を生成します。
ご興味あればお気軽にお問い合わせください。

-HAKADORI, その他
-, , , , ,