レンタルサーバー選びの迷いを解決!全力サポートします

Google or AdMax Promotion (srv)

XML,XSLT両方ネームスペース指定表示例(XMLサイトマップ+XSLT)【結局これか】

XML側に名前空間の指定を行い、XSLT(スタイルシート)にも
名前空間の指定をする両方指定の方法でGoogleがエラーにしない
XML仕様を満たしつつXSLTでHTML表示ができるように改善します。

本記事は以下の1コンテンツです。

XML,XSLT両方ネームスペース指定表示(XMLサイトマップ+XSLT)

これまでのサイトマップ、サイトマップインデックスの組み合わせでは、
Google側のXML仕様を満たしていないがスタイルシートが割り当てることができたり、
XML仕様を満たすとスタイルが反映できなかったりしました。

結果として以下の「検証3」部分で利用した、
XSLTスタイルシート側に名前空間と接頭辞を定義し、値ヘのアクセスは接頭辞を介して行う。

この方法以外に探し出すことができませんでした。(悔しい・・・でも仕様なのだろう・・・)

サイトマップインデックスの場合

サイトマップの場合の記述例です。

XML

以下のように指定しています。

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sm="http://www.sitemaps.org/schemas/sitemap/0.9">

XSLT

また要素へのアクセスも以下のように接頭辞を含ませて指定します。

<xsl:for-each select="sm:urlset/sm:url">
<tr>
<td><a target="_blank"><xsl:attribute name="href"><xsl:value-of select="sm:loc" /></xsl:attribute><xsl:value-of select="sm:loc" /></a></td>
<td><xsl:value-of select="sm:lastmod" /></td>
<td><xsl:value-of select="sm:changefreq" /></td>
<td><xsl:value-of select="sm:priority" /></td>
</tr>
</xsl:for-each>

適用済みの表示例

 

サイトマップの場合

サイトマップの場合の記述例です。

XML

以下のように指定しています。

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sm="http://www.sitemaps.org/schemas/sitemap/0.9">

XSLT

また要素へのアクセスも以下のように接頭辞を含ませて指定します。

<xsl:for-each select="sm:sitemapindex/sm:sitemap">
<tr>
<td><a target="_blank"><xsl:attribute name="href"><xsl:value-of select="sm:loc" /></xsl:attribute><xsl:value-of select="sm:loc" /></a></td>
<td><xsl:value-of select="sm:lastmod" /></td>
</tr>
</xsl:for-each>

適用済みの表示例

 

プロモーション

Google or AdMax Promotion (srvpos)

XML,XSLT両方ネームスペース指定の検証

上記のアプローチはよくみかけるサイトマップでも採用されていて、
特に珍しい書き方でもありません。

ですが、サイトマップであればこれで十分なのですが、
より複雑なXML変換を利用するようなケースでは極力接頭辞を省きたい。

そう思って、様々検討をしてみました。

以下はすべて「サイトマップ」を検証対象として利用しています。

様々な名前空間指定から見るパターン

ネームスペース(名前空間)をXML側に指定しないと、
Googleがエラー扱いにする反面、XMLに名前空間を指定すると、
XSLT(スタイルシート)が反映されないという困惑に直面することになります。

1.デフォルト名前空間指定例(絶対うまくいくだろ?でも適用されない)

XML側の名前空間指定に対しては以下を設定し、

<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

XSLT側の名前空間指定に対しては以下を設定するパターンです。

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

どちらも「xmlns="~"」形式で、
接頭辞(prefix/別名/エイリアス)を指定する形式「xmlns:prefix="~"」ではないので、
この指定方法の場合、デフォルト名前空間として文書全体が、
xmlns="~"」で指定した「~」部分の名前空間に属することになります。

双方が正しく一致しているのだから、これで問題ない・・・と思いますよね。
でもこの方法はNGです。

(前略)上記の場合、xmlns=http://www.w3.org/1999/xhtml を見ても気付かなかったり、あるいはこのデフォルト名前空間の宣言の前に他の多数の属性があるために、ワイドスクリーンで表示しているとしても例えば 167 列目の内容を見落してしまったりする可能性があります。html/head/title のような XPath 式を作成するのはごく当然のことですが、そのような式は空のノード・セットを返すことになります。入力文書には title のような要素が含まれていないためです。入力文書に含まれるすべての要素は http://www.w3.org/1999/xhtml 名前空間に属しています。XPath 式には、その点を反映しなければなりません。

XPath で名前空間が設定された要素にアクセスするには、該当する名前空間に接頭辞を定義する必要があります。例えば、サンプル XHTML 文書のタイトルにアクセスするには、XHTML 名前空間に接頭辞を定義し、その接頭辞をすべての XPath ステップで使用します。その方法を、リスト 4 のサンプル・スタイルシートに示します。

(抜粋引用)XSLT でありがちな失敗を避けるために|IBM developerWorks
(Evernote) アーカイブリンク

この記述による表示例は以下になりますが、うまく表示できません。

XML

XSLT

適用済みの表示例

表示は無言の真っ白表示です。

 

2.xpath-default-namespace指定(Version2.0ならこう書ける??)

上記リンク先には次のようにも書かれています。

残念ながら、XSLT バージョン 1.0 にはデフォルト名前空間と同じような概念はありません。そのため、名前空間の接頭辞を何度も繰り返さなければならなくなります。XSLT バージョン 2.0 ではこの問題が修正されていて、XPath 式で接頭辞が設定されていない要素に適用するデフォルト名前空間を指定することができます。さらに XSLT 2.0では、上記のスタイルシートはリスト 5 のように単純化されます。

リスト 5. XSLT 2.0 での XPath デフォルト名前空間の宣言

(抜粋引用)XSLT でありがちな失敗を避けるために|IBM developerWorks

 

Version2.0を指定してやることで「xpath-default-namespace」なるものを使い、
接頭辞が至るところに現れるのを避けることができるというのです。

実際にやってみますが、やはりうまく表示できません。

XML

XSLT

適用済みの表示例

惜しい、テーブルヘッダ表示まではいくものの列は空表示になってしまいます。

 

3.すべてに接頭辞を付加して要素にアクセス(多くはこれを採用)

多くのサイトマップなどで見かける指定方法として、
XSLT側で要素にアクセスする際にはすべて「接頭辞」を付加して指定する方法です。
前述の以下に従うアプローチです。

XPath で名前空間が設定された要素にアクセスするには、該当する名前空間に接頭辞を定義する必要があります。例えば、サンプル XHTML 文書のタイトルにアクセスするには、XHTML 名前空間に接頭辞を定義し、その接頭辞をすべての XPath ステップで使用します。その方法を、リスト 4 のサンプル・スタイルシートに示します。

(抜粋引用)XSLT でありがちな失敗を避けるために|IBM developerWorks

 

XML

以下のように指定しています。

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sm="http://www.sitemaps.org/schemas/sitemap/0.9">

XSLT

また要素へのアクセスも以下のように接頭辞を含ませて指定します。

<xsl:for-each select="sm:sitemapindex/sm:sitemap">
<tr>
<td><a target="_blank"><xsl:attribute name="href"><xsl:value-of select="sm:loc" /></xsl:attribute><xsl:value-of select="sm:loc" /></a></td>
<td><xsl:value-of select="sm:lastmod" /></td>
</tr>
</xsl:for-each>

適用済みの表示例

これは鉄板パターンなのでうまくいきます。

だからといってすべてに「sm:」を付けるとなるとミスりそうだし、
なんとか回避したい。デフォルトネームスペースを適用したいんですよね。。。

 

4.接頭辞を付加して宣言しつつデフォルトで要素にアクセス1(exclude-result-prefixes)

うまくいけばいいなと甘い期待を持って、宣言部は接頭辞を付ける。
でも、要素へのアクセスではデフォルトとしてアクセスしたいという記述を試行します。

これは以下を参考に試したものです。

これらの属性の値は、接頭辞を空白でつなげたリストです。
その属性に対して有効なnamespace宣言を利用して、 指定された接頭辞各々に結び付けられたnamespace各々に対して、 namespaceノードをresult文書にコピーしなくてよいことを示します。
この方法だと、デフォルトnamespaceには接頭辞がないので指定できません。 そこで、デフォルトnamespaceを表す特別な名前#defaultを接頭辞代わりに指定することによって、 デフォルトnamespaceに対して同様のことを行なうことができます。
例えば以下のように記述すると、 XHTMLとMathMLのnamespaceについては、namespaceノードがresult文書にコピーされません。

(抜粋引用) Studying XSLT — for advanced use — [ namespaceの除去 ]
(Evernote) アーカイブリンク

XML

以下のように指定しています。

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sm="http://www.sitemaps.org/schemas/sitemap/0.9"
exclude-result-prefixes="#default sm">

XSLT

また要素へのアクセスも以下のように接頭辞を省いて表示できないか試します。

<xsl:for-each select="sitemapindex/sitemap">
<tr>
<td><a target="_blank"><xsl:attribute name="href"><xsl:value-of select="loc" /></xsl:attribute><xsl:value-of select="loc" /></a></td>
<td><xsl:value-of select="lastmod" /></td>
</tr>
</xsl:for-each>

適用済みの表示例

こちらも、テーブルヘッダ表示まではいくものの列は空表示になってしまいます。
※version=”1.0″を指定していますが、version=”2.0″でも結果は同じです。

 

5.接頭辞を付加して宣言しつつデフォルトで要素にアクセス2(exclude-result-prefixes)

「exclude-result-prefixes」による指定は別のアプローチでも見かけます。
そのまま「exclude-result-prefixes=”sm”」のようにキャンセルするパターンです。

XML

以下のように指定しています。

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sm="http://www.sitemaps.org/schemas/sitemap/0.9"
exclude-result-prefixes="sm">

XSLT

また要素へのアクセスも以下のように接頭辞を省いて表示できないか試します。

<xsl:for-each select="sitemapindex/sitemap">
<tr>
<td><a target="_blank"><xsl:attribute name="href"><xsl:value-of select="loc" /></xsl:attribute><xsl:value-of select="loc" /></a></td>
<td><xsl:value-of select="lastmod" /></td>
</tr>
</xsl:for-each>

適用済みの表示例

やはり、テーブルヘッダ表示まではいくものの列は空表示になってしまいます。

 

 

何とか、接頭辞を省いた指定ができる方法があればといろいろ読み漁っては見たものの、
これといっていい解決策(抜け道?)には出逢えず、今回は調査終了としました。

まぁ素直に接頭辞付ければいい。それだけなんですけどね。

以下は参考です。

サイトマップの名前空間の定義と指定については以下の記述方法が参考になります。

(引用) xml – XSLT does not work when I include xmlns=”http://www.sitemaps.org/schemas/sitemap/0.9″ – Stack Overflow
(Evernote) アーカイブリンク

 

「exclude-result-prefixes」については以下のように書かれています。

exclude-result-prefixes
除外された名前空間としての名前空間 URI (Uniform Resource Identifier)。 値は、空白で区切られた名前空間プレフィックスのリストです。 プレフィックスに関連付けられた名前空間は、除外された名前空間として指定されます。 名前空間プレフィックスのリストに #default を含めることによって、(xmlns によって宣言された) 既定の名前空間を、除外された名前空間として指定できます。 名前空間の除外された名前空間としての指定は、exclude-result-prefixes を持つ要素をルートとするスタイル シートのサブツリー内でのみ有効です。 要素をルートとするサブツリーには、その 要素の子によってインポートまたはインクルードされたスタイル シートは含まれません。

(引用) <xsl:stylesheet> 要素
(Evernote) アーカイブリンク

 

どうもこの「exclude-result-prefixes」ちゃんと使えば便利そうなんですけど、
どうにも使いどころが分からなかったという印象です。

 


AdMax Promotion

公開日:

コンテンツナビ
すべて展開 | すべて省略

AdMax Promotion

カテゴリ
すべて展開 | すべて省略

QRコードからもこのURLを開けます。