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

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

新規登録して質問してみよう
ただいま回答率
85.50%
XPath(XML Path)

XML Path Language (XPath; XMLパス言語)は、マークアップ言語 XML に準拠した文書の特定の部分を指定する言語構文の事をいいます。XPathはXMLとは別の構文を使用します。XMLドキュメントの抽象、論理ストラクチャ上で動作します。

XSLT

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

Q&A

解決済

1回答

2369閲覧

xmlデータの検索と構造解析にxsltを使おうとしたのですが…

KojiDoi

総合スコア13669

XPath(XML Path)

XML Path Language (XPath; XMLパス言語)は、マークアップ言語 XML に準拠した文書の特定の部分を指定する言語構文の事をいいます。XPathはXMLとは別の構文を使用します。XMLドキュメントの抽象、論理ストラクチャ上で動作します。

XSLT

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

0グッド

2クリップ

投稿2017/09/14 04:35

###前提・実現したいこと
非常に複雑な構造をもったXMLファイルから必要なデータを抜き出して利用したいと思っています。
しかし、データ構造などに関する充分な資料がなく、目当てのデータがどこに含まれているかを調べるところから始めなければなりません。
目当てのキーワードは複数の異なる文脈で使用されていることがわかっています。したがって、単にそのキーワードについて検索するだけではなく、それがどのようなタグの下に書かれているかも把握しなければなりません。これをxsltとxpathを利用して簡素に実現できないかと考えました。

###発生している問題
そこで、後述のように、xsltファイルを作ってみたのですが実行結果は微妙に期待とずれております。その原因と対策をお教えいただければ嬉しく思います。xsltなんか使わなくてもこうすれば簡単だよ!的なアドバイスも大歓迎です。

###該当のソースコードとデータ
テストデータ(test.xml)

xml

1<?xml version="1.0" encoding="UTF-8"?> 2<xml> 3<node1 id="node1_1"> 4 <node2 id="node2_1"> 5 abcd 6 </node2> 7 <node2 id="node2_2"> 8 <node3 id="node3_1"> 9 xxxx 10 </node3> 11 </node2> 12</node1> 13<node1 id="node1_2"> 14 <node2 id="node2_3"> 15 cccc 16 <node3 id="node3_2"> 17 xxxx 18 </node3> 19 </node2> 20</node1> 21</xml>

某サイトの記事を参考に、"xxxx"という文字列を含むノードをリストアップすべく見よう見まねで書いてみたxsltデータ(test.xsl)

xml

1<?xml version="1.0" encoding="utf-8"?> 2<!-- https://stackoverflow.com/questions/12369734/get-all-ancestors-of-current-node --> 3<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 4 <xsl:template match="/"> 5 <xsl:variable name="curr" select="//*[contains(text(),'xxxx')]"></xsl:variable> 6 <xsl:variable name="test1" select="$curr/self::*"></xsl:variable> 7 <xsl:for-each select="$test1"> 8start 9 <xsl:value-of select="concat(name(), ': ID=', @id)"></xsl:value-of> 10 <xsl:variable name="test2" select="$test1/ancestor::*"></xsl:variable> 11 <xsl:for-each select="$test2"> 12 ancestor 13 <xsl:value-of select="concat(name(), ': ancestorID=', @id)"></xsl:value-of> 14 </xsl:for-each> 15end 16 </xsl:for-each> 17 </xsl:template> 18</xsl:stylesheet>

###試したこと
次のようにコマンドを実行してみました。

xsltproc ~/work/test.xsl ~/work/test.xml

すると、次のような結果が得られます。

<?xml version="1.0"?> start node3: ID=node3_1 ancestor xml: ancestorID= ancestor node1: ancestorID=node1_1 ancestor node2: ancestorID=node2_2 ancestor node1: ancestorID=node1_2 ancestor node2: ancestorID=node2_3 end start node3: ID=node3_2 ancestor xml: ancestorID= ancestor node1: ancestorID=node1_1 ancestor node2: ancestorID=node2_2 ancestor node1: ancestorID=node1_2 ancestor node2: ancestorID=node2_3 end

惜しいところですが、余計な兄弟のデータが一生に出力されており、これでは使えません。私としては次のような出力を期待しているのです。

<?xml version="1.0"?> start node3: ID=node3_1 ancestor xml: ancestorID= ancestor node1: ancestorID=node1_1 ancestor node2: ancestorID=node2_2 end start node3: ID=node3_2 ancestor xml: ancestorID= ancestor node1: ancestorID=node1_2 ancestor node2: ancestorID=node2_3 end

###補足情報(言語/FW/ツール等のバージョンなど)
環境:CentOS 6.6

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

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

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

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

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

guest

回答1

0

自己解決

自己解決!

進捗がありました。以下のxlstによって、所定のキーワードを含むノード+その上位ノードの表示が一応達成できました。

この結果を利用し、改めてxpath式を組み、perl+xml::xpathあたりを利用してデータ取得・二次利用を実現できそうです。

xml

1<?xml version="1.0" encoding="utf-8"?> 2<!-- https://stackoverflow.com/questions/12369734/get-all-ancestors-of-current-node --> 3<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 4 <xsl:template match="/"> 5 <xsl:variable name="curr" select="//*[contains(text(),'xxxx')]"></xsl:variable> 6 <xsl:variable name="test1" select="$curr/self::*"></xsl:variable> 7 <xsl:for-each select="$test1"> 8found item 9 <xsl:value-of select="concat('node=', name(), ' ID=', @id)"></xsl:value-of> 10 <xsl:variable name="test2" select="./ancestor::*"></xsl:variable> 11 <xsl:for-each select="$test2"> 12 <xsl:value-of select="concat(' ancestorNode=', name(), ' ancestorID=', @id)"></xsl:value-of> 13 </xsl:for-each> 14 </xsl:for-each> 15 </xsl:template> 16</xsl:stylesheet> 17

質問文に示したバージョンからの重要な変更点は以下です。

XML

1<xsl:variable name="test2" select="./ancestor::*">

これで余計な兄弟ノードをたどることはなくなりました。

データファイル

XML

1<xml> 2<node1 id="node1_1"> 3 <node2 id="node2_1"> 4 abcd 5 </node2> 6 <node2 id="node2_2"> 7 <node3 id="node3_1"> 8 xxxx 9 </node3> 10 </node2> 11</node1> 12<node1 id="node1_2"> 13 <node2 id="node2_3"> 14 cccc 15 <node3 id="node3_2"> 16 xxxx 17 </node3> 18 </node2> 19</node1> 20<node1 id="node1_3"> 21xxxx 22</node1> 23</xml>

実行結果

$ xsltproc_lite test.xsl test.xml /dev/stdout [ ~/work ] <?xml version="1.0"?> found item node=node3 ID=node3_1 ancestorNode=xml ancestorID= ancestorNode=node1 ancestorID=node1_1 ancestorNode=node2 ancestorID=node2_2 found item node=node3 ID=node3_2 ancestorNode=xml ancestorID= ancestorNode=node1 ancestorID=node1_2 ancestorNode=node2 ancestorID=node2_3 found item node=node1 ID=node1_3 ancestorNode=xml ancestorID=

投稿2017/09/15 14:52

KojiDoi

総合スコア13669

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問