teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

xpath 例

2020/06/21 19:38

投稿

KojiDoi
KojiDoi

スコア13727

answer CHANGED
@@ -8,4 +8,99 @@
8
8
  xmllint sample.xml
9
9
  ```
10
10
 
11
- こんな感じで実行して、問題なくxmlデータが出力されればいいのですが、掲出のデータではエラーメッセージが出るはずです。これをまず潰してください。
11
+ こんな感じで実行して、問題なくxmlデータが出力されればいいのですが、掲出のデータではエラーメッセージが出るはずです。これをまず潰してください。
12
+
13
+ # xpathを検討してみる
14
+
15
+ 便宜上、中身を簡略化した次のようなテスト用データで考えてみます。
16
+
17
+ ```xml
18
+ <?xml version="1.0" encoding="UTF-8"?>
19
+ <!-- test200622a.xml -->
20
+ <BioSampleSet>
21
+ <BioSample> <!-- 理想を体現したノード -->
22
+ <Ids>
23
+ <Id>id1</Id>
24
+ </Ids>
25
+ <Attributes>
26
+ <Attribute attribute_name="strain">DOA9</Attribute>
27
+ <Attribute attribute_name="material">soil</Attribute>
28
+ </Attributes>
29
+ </BioSample>
30
+ <BioSample> <!-- idは上と同じだがmaterialがないノード -->
31
+ <Ids>
32
+ <Id>id1</Id>
33
+ </Ids>
34
+ <Attributes>
35
+ <Attribute attribute_name="strain">XXXX</Attribute>
36
+ </Attributes>
37
+ </BioSample>
38
+ <BioSample> <!-- idは上と違いmaterialがあるノード -->
39
+ <Ids>
40
+ <Id>id2</Id>
41
+ </Ids>
42
+ <Attributes>
43
+ <Attribute attribute_name="strain">YYYY</Attribute>
44
+ <Attribute attribute_name="material">soil</Attribute>
45
+ </Attributes>
46
+ </BioSample>
47
+ </BioSampleSet>
48
+ ```
49
+
50
+ 私の環境ではperlのXML::Pathモジュールに付随した`xpath`というツールが入っているのでこれを使いますが、xpathの書式はxmllintでも同じです。
51
+
52
+ ここではId="id1"なノードをまず探してみることにします。
53
+
54
+ ```
55
+ % xpath -e '//Id[text()="id1"]' test200622.xml
56
+ Found 2 nodes in test200622.xml:
57
+ -- NODE --
58
+ <Id>id1</Id>
59
+ -- NODE --
60
+ <Id>id1</Id>
61
+ ```
62
+ 次に、最終的にたどり着きたいノードAttributeと出発点のIdの位置関係を確認します。両ノードの共通祖先はBioSampleで、これはIdから見て2世代上になります。そこで、Idから二つ遡ったノードにアクセスするXpathを考えます。
63
+
64
+ ```
65
+ xpath -e '//Id[text()="id1"]/../..' test200622.xml [ ~/work ]
66
+ Found 2 nodes in test200622.xml:
67
+ -- NODE --
68
+ <BioSample> <!-- 理想を体現したノード -->
69
+ <Ids>
70
+ <Id>id1</Id>
71
+ </Ids>
72
+ <Attributes>
73
+ <Attribute attribute_name="strain">DOA9</Attribute>
74
+ <Attribute attribute_name="material">soil</Attribute>
75
+ </Attributes>
76
+ </BioSample>
77
+ -- NODE --
78
+ <BioSample> <!-- idは上と同じだがmaterialがないノード -->
79
+ <Ids>
80
+ <Id>id1</Id>
81
+ </Ids>
82
+ <Attributes>
83
+ <Attribute attribute_name="strain">XXXX</Attribute>
84
+ </Attributes>
85
+ </BioSample>
86
+ ```
87
+
88
+ さらにAttributeにおりていく記述を追加します。相手にするのは"material"なAttributeなので、制約条件を付けます。
89
+
90
+ ```
91
+ xpath -e '//Id[text()="id1"]/../..//Attribute[@attribute_name="material"]' test200622.xml [ ~/work ]
92
+ Found 1 nodes in test200622.xml:
93
+ -- NODE --
94
+ <Attribute attribute_name="material">soil</Attribute>
95
+ ```
96
+
97
+ タグの中身だけあればいいので、
98
+
99
+ ```
100
+ xpath -e '//Id[text()="id1"]/../..//Attribute[@attribute_name="material"]/text()' test200622.xml [ ~/work ]
101
+ Found 1 nodes in test200622.xml:
102
+ -- NODE --
103
+ soil
104
+ ```
105
+
106
+ 複数のIDについて処理し、なおかつIDと結果の対応がわかるように出力するためには、xpathの外で仕掛けを作る必要があるでしょう。