---
title: "組み込みのXPath関数を使用する"
date: "2011-07-12"
categories: 
  - "xpath"
tags: 
  - "altova-online-training"
  - "altova-xmlspy"
  - "data-mapping"
  - "education"
  - "learn-xml"
  - "xml-editor"
  - "xmlspy"
  - "xpath"
  - "xslt"
description: この記事では、XPath関数を使用してXMLデータを効率的にソートする方法について解説します。特に、姓の抽出と、タイトルに含まれる冠詞の処理に焦点を当てています。
---
Status: #blog

Tags:  #altova-online-training #altova-xmlspy #data-mapping #education #learn-xml #xml-editor #xmlspy #xpath #xslt

Categories: [xpath+xquery](/blog/ja/category/xpathxquery.md)
# 組み込みのXPath関数を使用する

以下に、あるものを開発するにあたって、 [Altova オンライン研修プログラム](https://www.altova.com/ja/aot/online-training.aspx) コースのデータにおいて、書籍を著者名で並べ替える際に、著者名がフルネームの文字列として扱われていることに気づきました。そのため、書籍は文字列の最初の文字、つまり著者の姓で並べ替えられていました。この並び順を修正することは、今回のコースの範囲外でしたが、XPath関数を使用することで、文字列から姓を簡単に抽出して、並べ替えのキーとして利用することができます。次に、書籍のタイトルを二次的な並べ替えキーとして使用しようとすると、「A」、「An」、または「The」で始まるタイトルが問題となります。私は、タイトルを二次的な並べ替えキーとして使用したいのですが、先頭の定冠詞や不定冠詞は無視したいと考えています。

![XPath式を使用してソートを修正し、書籍リストを出力します](https://lh4.ggpht.com/-OBe9_xfjlpQ/TgD1tUSi6sI/AAAAAAAAAGw/nLwMwUDQTJ4/correct-sort-xsl2_thumb%25255B2%25255D.png?imgmax=800) 

このXSLTコードがどのように作成されたのか、見ていきましょう。この記事は、[XMLSpy](https://www.altova.com/ja/xmlspy.html)をプラットフォームとして使用して作成されましたが、同じXPath式を[MapForce](https://www.altova.com/ja/mapforce.html)や[StyleVision](https://www.altova.com/ja/stylevision.html)内でも使用することで、同様の結果を得ることができます。まずは、シンプルなXML形式の書籍リストから始めましょう。ここでは、著者名とタイトルを持つ4つの書籍データを用意します。 

[![3冊の本のリスト](https://lh5.ggpht.com/-oP0T7tap1j8/TgD1qZFjeJI/AAAAAAAAAGI/Q9N1sefXpr8/book-list-xml2_thumb%25255B6%25255D.png?imgmax=800 "book_list.xml")](http://lh5.ggpht.com/-1XkQTBtjxgI/TgD1p7e9jRI/AAAAAAAAAGE/r5x-fYqrXB4/s1600-h/book-list-xml2%25255B8%25255D.png) 

XSLTを使って書籍のリストを作成する場合、以下のようなコードになります

[![ソートせずに書籍リストを出力します](https://lh6.ggpht.com/-Xl2drxDYvWk/TgD1qyCS-tI/AAAAAAAAAGQ/XtlE-ha3aPY/no-sort-xsl2_thumb%25255B3%25255D.png?imgmax=800 "no_sort.xsl")](http://lh6.ggpht.com/-0QjJb5fadso/TgD1qitzcrI/AAAAAAAAAGM/ENp-px5_e1g/s1600-h/no-sort-xsl2%25255B7%25255D.png) 

これにより、以下の結果が出力されます 

[![未整理の書籍リスト](https://lh4.ggpht.com/-84ZeFnOVnX0/TgD1ruHFFII/AAAAAAAAAGY/rtui-dgtCUQ/no-sort-output_thumb%25255B2%25255D.png?imgmax=800 "Output from XSL with No Sort")](http://lh6.ggpht.com/-DcGmqHHaQi4/TgD1rJWB_GI/AAAAAAAAAGU/V9i4088XoKs/s1600-h/no-sort-output%25255B4%25255D.png) 

これらの書籍は、元のデータファイルに記載されている順序で出力されます。もし、`xsl:for-each`ループに`xsl:sort`を追加すれば、出力の順序を他の方法で調整することができます。 

[![基本的なソート機能を使って、書籍リストを出力します](https://lh4.ggpht.com/-JX9qbo9fYjo/TgD1sKu_YVI/AAAAAAAAAGg/rtHXnh_x94o/sort-xsl2_thumb%25255B2%25255D.png?imgmax=800 "sort.xsl")](http://lh4.ggpht.com/-WEIuCC1NRNw/TgD1rzIgzPI/AAAAAAAAAGc/q79Va9UWMgo/s1600-h/sort-xsl2%25255B4%25255D.png) 

これにより、ソートされたリストが生成されますが、完全に正しくソートされているわけではありません。 

[![XSLによる基本的なソート処理の結果](https://lh3.ggpht.com/-kN0aSY1DhE8/TgD1spmsmLI/AAAAAAAAAGo/BsxQW6XYwWk/sort-output_thumb%25255B2%25255D.png?imgmax=800 "Output from XSL with Basic Sort")](http://lh3.ggpht.com/-2JAA_7dIt4o/TgD1sYIFl-I/AAAAAAAAAGk/M5g2B1vVC_M/s1600-h/sort-output%25255B4%25255D.png) 

著者を文字列としてソートすると、「ジュール・ヴェルヌ」が「マーク・トウェイン」の前に表示されます。また、「アーサー王の宮廷に現れたコネチカット人」が「ハックルベリー・フィンの冒険」の前に表示されます。私たちは、不定冠詞「A」を無視して、「ハックルベリー・フィンの冒険」を「アーサー王の宮廷に現れたコネチカット人」の前に表示したいと考えています。XPath式を使用して、必要なソートキーを抽出することができます。 

[![XPath式を使用してソートを修正し、書籍リストを出力します](https://lh4.ggpht.com/-OBe9_xfjlpQ/TgD1tUSi6sI/AAAAAAAAAGw/nLwMwUDQTJ4/correct-sort-xsl2_thumb%25255B2%25255D.png?imgmax=800 "correct_sort.xsl")](http://lh4.ggpht.com/-1797dSMl6G0/TgD1tIvfZnI/AAAAAAAAAGs/G8i7ztztp9Y/s1600-h/correct-sort-xsl2%25255B4%25255D.png) 

コードの出力を見てみる前に、まずコードを詳しく見ていきましょう。ここでは、「author」を「reverse(tokenize(author, ' '))[1]」に置き換えています。`tokenize`関数は、指定された区切り文字（ここでは単一の空白）を使って、文字列をトークンに分割します。したがって、「Jules Verne」は「Jules」と「Verne」に分割されます。`reverse`関数は、トークンの順番を逆にして「Verne」と「Jules」の順になります。そして、角括弧内の「[1]」は、リストの最初の要素である「Verne」を選択します。この値が、`xsl:sort`関数で使用され、書籍を並び替えるために使用されます。これは完璧な解決策ではありませんが、今回のケースでは機能します。タイトルに関する処理は複雑に見えますが、ロジック自体は単純です。`tokenize(title, ' ')[1]`という式は、タイトルの最初の単語を抽出します。最初の条件分岐は、「タイトルの最初の単語が「A」であるか？」というものです。もしそうであれば、タイトルの3文字目から始まる部分文字列を返します。これにより、「A」とそれに続く空白が削除されます。もしタイトルの最初の単語が「A」でない場合、次に「タイトルの最初の単語が「The」であるか？」という条件でチェックを行います。もしそうであれば、タイトルの5文字目から始まる部分文字列を使用します。これにより、「The」とそれに続く空白が削除されます。もしどちらの条件も満たされない場合、タイトルをそのままソートキーとして使用します。「An」という単語についても、同様のチェックを追加することも可能ですが、今回のデータセットでは必要ありません。この最後のXSLTを実行すると、以下の出力が得られます。 

[![XSL処理後の出力（ソートが修正済み）](https://lh5.ggpht.com/-78G5M2Z81Ow/TgD1uRmfiQI/AAAAAAAAAG4/YStPJ1HRDj0/correct-sort-output_thumb%25255B2%25255D.png?imgmax=800 "Output from XSL with Corrected Sort")](http://lh3.ggpht.com/-h5AD7I5C60o/TgD1tsVI9fI/AAAAAAAAAG0/Nj8_cO10i2s/s1600-h/correct-sort-output%25255B4%25255D.png) 

「マーク・トウェイン」が現在、「ジュール・ヴェルヌ」よりも上位に表示されています。「ハックルベリー・フィンの冒険」は、「カラベラス郡の有名な飛び蛙」や「アーサー王宮廷のコネチカット人」よりも上位に表示されています。著者名の並び順に関する私たちの手法の欠点は、著者名を「ジュール・ヴェルヌ」を「Verne, Jules」として扱うようにしたいという点です。そうすることで、もし「ジミー・ヴェルヌ」という著者の本があった場合、それらは異なる著者として扱われるはずです。しかし、現在のコードではそれが実現されていません。`concat(reverse(tokenize(author, ' '))[1], reverse(tokenize(author, ' '))[2])`を使用することで、「ジュール・ヴェルヌ」と「ジミー・ヴェルヌ」を正しく並べ替えることができますが、この解決策は2単語の著者名にしか適用できません。もし著者が姓名に付記（「マーティン・ルーサー・キング・ジュニア」など）や複数の単語（「ジョージ・ハーバート・ウォーカー・ブッシュ」など）を持つ場合、このコードは機能しません。著者名のアルファベット順に関する一般的なルールには多くの例外があり、すべてのバリエーションに対応できるコードを作成するには、この記事の範囲をはるかに超える複雑さが必要です。今回示したかったのは、XPath式を使用して、XMLデータを動的に操作する能力です。データソースの形式を常に完全に制御できるわけではありませんが、XPath式の強力さを利用することで、必要な形式にデータを変換することができます。これらの例で使用したファイルのコピーは[こちら](https://www.altova.com/ja/library/Using_XPath_Functions.zip)から入手できます。
