質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
XSLT

XSLTは、組み立てられた文書を(XML、HTML、そしてプレーンテキストのような)別のフォーマットに変化する為にデザインされたXMLの為の変換用言語です。

Q&A

解決済

1回答

1068閲覧

リンクファイルに名前空間を加えることなく、目的の情報が取得したい。

UG_ito_Pcorp

総合スコア13

XSLT

XSLTは、組み立てられた文書を(XML、HTML、そしてプレーンテキストのような)別のフォーマットに変化する為にデザインされたXMLの為の変換用言語です。

0グッド

0クリップ

投稿2020/06/04 07:13

どうして名前空間が必要ですか?

WORDからOOXMLを抽出すると、画像などのリンク情報が別ファイル(document.xml.rels)に書き込まれます。XSLTでリンクファイル名を取得する際、このファイルへアクセスしますが、単にアクセスしても情報を取得することがなぜかできません。

変換対象のXML:

<w:body> <w:p> <w:r> <w:drawing> <wp:inline distT="0" distB="0" distL="0" distR="0"> <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"> <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"> <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"> <pic:blipFill> <a:blip r:embed="rId7"> <a:extLst/> </a:blip> </pic:blipFill> </pic:pic> </a:graphicData> </a:graphic> </wp:inline> </w:drawing> </w:r> </w:p> </w:body>

リンク情報のファイル(document.xml.rels):

<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"> <Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image1.png"/> </Relationships>

作成したXSLT(抜粋):

<xsl:variable name="Relationships" select="document('_rels/document.xml.rels')"/> <xsl:template match="w:drawing"> <fig> <image> <xsl:attribute name="href"> <xsl:variable name="embed_id" select="descendant::a:blip/@r:embed"/> <xsl:for-each select="$Relationships//Relationship"> <xsl:variable name="RelationshipId" select="@Id"/> <xsl:choose> <xsl:when test="$embed_id = $RelationshipId"> <xsl:value-of select="@Target"/> </xsl:when> </xsl:choose> </xsl:for-each> </xsl:attribute> </image> </fig> </xsl:template>

出力されるXML:

<fig> <image href=""/> </fig>

<image>のhref属性が空になってしまいます。
そこで(知識不足ゆえ)何の根拠もなく、リンク情報のファイルに名前空間を加えてみたところ、目的の情報を取得することができました。

手を加えたリンク情報のファイル(document.xml.rels):

<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"> <r:Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image1.png"/> </Relationships>

※名前空間の宣言追加と<Relationship>タグの変更をしました。

変更したXSLT(抜粋):

<xsl:for-each select="$Relationships//r:Relationship">

※selectの内容を「select="$Relationships//Relationship"」から「select="$Relationships//r:Relationship"」に変更しました。

出力されたXML:(目的が達成された出力)

<fig> <image href="media/image1.png"/> </fig>

何が原因で、名前空間なしでは、目的の情報を得ることができないのでしょうか。
リンク情報のファイル(document.xml.rels)に手を加えることなく、目的の出力を得たいのですが、どうすればよいかご教授いただけないでしょうか。
また、そもそもトンチンカンなことをしているようであれば、ご指摘いただけると助かります。
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

与えられているコードですが、実際に動かしてみるまでがやや億劫に感じます(省略部分を補いつつ LibreOffice で再現に必要なファイルは生成できますが……)。

そこで、やや一般化した問題について考えてみました。
恐らくご質問の件にも応用できると予想します。

課題

まずはファイルの配置について紹介します。

ファイル構成

$ exa -T . ├── index.xml ├── main.xsl ├── Rakefile └── sub.xml

実行

$ rake

実行後のファイル構成

$ exa -T . ├── index.xml ├── main.xsl ├── public <- generated │ └── index.xml <- generated ├── Rakefile └── sub.xml

ファイル内容

さて、以下ではそれぞれのファイルの中身について言及していきます。

なんらかの XML があるとします。
この XML はなんでも良さそうですね。

index.xml:

xml

1<?xml version="1.0"?> 2<aaa></aaa>

そして、以下の XSLT を変換に使います。

main.xsl(修正前):

xml

1<?xml version="1.0"?> 2<xsl:stylesheet 3 version="1.0" 4 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 5 6 <xsl:variable name="sub" select="document('sub.xml')"/> 7 <xsl:template match="/"> 8 <xxx> 9 <xsl:value-of select="$sub/sss"/> 10 </xxx> 11 </xsl:template> 12</xsl:stylesheet>

XSLT から sub.xml を呼びだして変数に束縛していますので、 sub.xml を用意します。
これはいくらか中身があります。

おまけにこの XML にはトップレベルの DOM ノードに名前空間が付いています。
本課題はこの名前空間が罠なのです。

sub.xml:

xml

1<?xml version="1.0"?> 2<sss xmlns="http://this.is.url">uuu</sss>

以上を素朴に XSLT 変換してみましょう。
手順は Rakefile に書いておきました。

Rakefile:

ruby

1# frozen_string_literal: true 2 3TARGET = 'public/index.xml' 4 5task default: TARGET 6 7file TARGET => ['main.xsl', 'index.xml', 'sub.xml', 'public'] do |t| 8 sh %(xsltproc -o #{t.name} #{t.source} #{t.sources[1]}) 9end 10 11directory 'public'

$ rake して得られた結果は以下です。
予期したものではありませんね。

public/index.xml:

xml

1<?xml version="1.0"?> 2<xxx/>

解決

以下のようにします。
変更するのは XSLT だけで済みます。

main.xsl:

xml

1<?xml version="1.0"?> 2<xsl:stylesheet 3 version="1.0" 4 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 5 xmlns:s="http://this.is.url" 6 exclude-result-prefixes="s"> 7 8 <xsl:variable name="sub" select="document('sub.xml')"/> 9 <xsl:template match="/"> 10 <xxx> 11 <xsl:value-of select="$sub/s:sss"/> 12 </xxx> 13 </xsl:template> 14</xsl:stylesheet>

それでは $ rake して結果を見てみましょう。

public/index.xml:

xml

1<?xml version="1.0"?> 2<xxx>uuu</xxx>

うまくいっているようですね。

参考

詳しくは W3C の名前空間周りの記述をご覧ください。

今回のポイントは XSLT で sub.xml に含まれている ID (URI) に言及したことです。
もちろんそれに伴って定義する名前空間は XSLT の XPath にも前置することになります。

投稿2020/06/25 10:58

編集2020/06/25 11:01
gemmaro

総合スコア358

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

UG_ito_Pcorp

2020/06/26 06:38

ご教授、ありがとうございました。 ご指摘のとおり、リンク情報で宣言されている名前空間に適当な(今回は"rel”としました)接頭辞を付けて、これをXSLTで宣言することで解決いたしました。(該当箇所のXPathにも) なぜ、このような処理が必要か…までは理解が及んでおりませんが、取り急ぎ、経験値として学ばせていただきます。 「実際に動かしてみるまでがやや億劫に…」についても、今後はすぐに実行できるサンプルなどを用意して質問するよう心がけます。また、ご回答いただける機会がございましたら、よろしくお願いいたします。
gemmaro

2020/06/26 07:21

こちらこそ興味深い質問をありがとうございました。また、今後回答・質問させていただく際にはよろしくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問