- PR -

xpathでの完全一致の検索式は不可能なのでしょうか?

1
投稿者投稿内容
yozuki
会議室デビュー日: 2007/10/01
投稿数: 3
投稿日時: 2007-10-02 11:55
初心者です。

■検索構造
<group>
<item name="a" />
</group>

上記のXMLデータと構造が完全に一致するものを検索するXpathを考えています。

//group/item[@name='a']
上記の場合、下記の検索対象全てのgroupノードが抽出されてしまいます。

■検索対象
<data>
<group>
<item name="a" />
</group>
<group>
<item name="a" >
<item name="x" />
</item>
</group>
<group>
<item name="a" />
<item name="b" />
</group>
<group>
<item name="a" age="20"/>
</group>
</data>
※構造の規則として、
・group以下にはitemが1個以上ある。
・itemにはname属性が1個ある。
・itemにはname属性以外の任意の属性が0個以上ある。


■検索結果として
<group>
<item name="a" />
</group>
だけのような検索結果がほしいのですが、どのようなXpathがよいのでしょうか?

また、xpathだけでは完全一致検索ができない場合、
完全一致検索を実現する実装方法としてどのような方法があるのでしょうか?
ご教授よろしくお願いします。
るぱん
ぬし
会議室デビュー日: 2003/08/01
投稿数: 1370
投稿日時: 2007-10-02 12:54
るぱんです。

どういう背景で、何をしようとしていて、
結果がどうなったのかがあいまいです。

〜参考〜
簡単な実行結果
ExcelVBAでやってます。
Excelのシートの画面でAlt+F11→挿入→標準モジュール
その画面にコードを貼り付けてみてください。

尚、先程のXMLをCドライブ直下に「test.xml」として配置しました。
コード:

Sub MacrTemp()
Dim domDoc As DOMDocument30
Dim domNode As IXMLDOMNode

Set domDoc = CreateObject("MSXML2.DOMDocument")

domDoc.Load ("C:\test.xml")

For Each domNode In domDoc.selectNodes("//group/item[@name='a'] ")
Debug.Print domNode.xml
Debug.Print "★"
Next
End Sub



実行結果
コード:

<item name="a"/>

<item name="a">
<item name="x"/>
</item>

<item name="a"/>

<item name="a" age="20"/>





[ メッセージ編集済み 編集者: るぱん 編集日時 2007-10-02 12:57 ]
MMX
ぬし
会議室デビュー日: 2001/10/26
投稿数: 861
投稿日時: 2007-10-02 14:39
//group[count(*)=1]/item[@name='a'][count(@*)=1]
yozuki
会議室デビュー日: 2007/10/01
投稿数: 3
投稿日時: 2007-10-02 15:43
すみませんでした、説明漏れです。


やりたい事→XMLの構造検索をします。(完全一致)


先ほどの投稿の検索対象にあるデータの補足説明です。
※構造の規則として
・itemは0個以上の兄弟ノードを持ち、0個以上の子ノード持つ。


実データはitemどうし、すごく複雑に枝分かれしています。

ですので、
■検索構造
<group>
<item name="a" />
</group>
は検索できる最少値の構造になります。

これ以外を検索結果に出したくないのです。

以下のような構造がデータにあったとしても。
<data>
<group>
<item name="a" >
<item name="a" >
<item name="a" />
</item>
</item>
</group>
<group>
<item name="a" >
<item name="a" >
<item name="a" />
</item>
<item name="a" />
</item>
</group>
</data>

itemの子ノードにitemがx個、または無し
なんて指定する方法はあるのでしょうか?

重ね重ねよろしくご教授願います。
MMX
ぬし
会議室デビュー日: 2001/10/26
投稿数: 861
投稿日時: 2007-10-02 15:57
> itemの子ノードにitemがx個、または無し
item[(count(item)=x) or count(item)=0]
XSLT用語 コンテキストノード、カレントノード
------
//group[item[position(.)=1 and @name='a' ][count(*)=0]][count(*)=1]
こんな式を 検索の xml から発生するのがいいかも
一度にすると 長さ制限に引っかかりそう。
position関数で 出現順も 比較できます。
(じゃんじゃん追加)

[ メッセージ編集済み 編集者: MMX 編集日時 2007-10-02 16:52 ]
MMX
ぬし
会議室デビュー日: 2001/10/26
投稿数: 861
投稿日時: 2007-10-02 16:16
構造を渡り歩く 場合の ヒント
http://www.infoteria.com/jp/contents/xml-data/REC-xslt-19991116-jpn.htm#copying
の 自分自身の変換は を熟読
で 比較対象を document関数で変数に読み込んで
1.頭出し
2.そこから再帰で掘り下げながら name比較
そんな感じかな

xsltじゃなく DOMで ノードをトラバースの練習問題を 下敷きにしたほうが
簡単かも
-----
検索されるxml データが 大量の場合は XML専用のDBを使うと高速です
構造検索用の インディクスをデータ格納時に作っておくそうです。
-----
http://www.infoteria.com/jp/contents/xml-data/REC-xslt-19991116-jpn.htm
XSLT1.0 の 要約
XSLT は、XML 用のスタイルシート言語である XSL の一部として使用するために設計された。
(書式を当てたり、目次や索引を作るということ)
しかし、XSLT は 完全に汎用的な XML 変換用言語として使用するために設計されたわけではない。
むしろ設計の主眼は、
XSL の一部として XSLT を 使用する際に必要となる変換処理を行うことにある。

XSLTで 構造検索が 作りにくいのは「仕様です」



[ メッセージ編集済み 編集者: MMX 編集日時 2007-10-02 17:11 ]
るぱん
ぬし
会議室デビュー日: 2003/08/01
投稿数: 1370
投稿日時: 2007-10-02 16:21
るぱんです。

おさらい。
ExcelVBAでやってます。
Excelのシートの画面でAlt+F11→挿入→標準モジュール
その画面にコードを貼り付けてみてください。

設定が抜けてた。汗

更に、ツール→参照設定
Microsft XML,v6.0
を追加。

もし、選択候補に無い場合は、
MicrosftのDownloadCenterに無料で落ちてるので、
Googleで「MSXML 6.0」を検索し、Installしてみてください。
選択候補に現れるはずです。
コード:

Sub MacrTemp()
Dim domDoc As DOMDocument60
Dim domNode As IXMLDOMNode

Set domDoc = New DOMDocument60

domDoc.Load ("C:\test.xml")

' For Each domNode In domDoc.selectNodes("//group/item[@name='a'] ")
' Debug.Print domNode.xml
' Debug.Print "★"
' Next

For Each domNode In domDoc.selectNodes("//group[count(*)=1 and ./item[@name='a'][count(*)=0]]")
Debug.Print domNode.xml
Debug.Print "★"
Next
Stop

End Sub


実行結果
コード:

<group>
<item name="a"/>
</group>

<group>
<item name="a" age="20"/>
</group>




で、やりたいことについてだけど、
同じ要素名の入れ子は混乱するから止めたほうが良いと思う。

例えば、itemならこうだ・・・と決めておいて、
コード:

<item>
<name>商品名</name>
<price>20000</price>
<publish-date>2007/10/02</publish-date>
</item>


ジャンル毎の構造に差し込んでやる・・・って考えると楽かもね。
コード:

<os id='windows'>
<database>
<oracle/>
<mySql/>
<postgreSql/>
</database>
</os>


実際に差し込んでみると・・・。
コード:

<os id='windows'>
<item>
<name>商品名</name>
<price>20000</price>
<publish-date>2007/10/02</publish-date>
</item>
<database>
<oracle>
<item>
<name>商品名</name>
<price>20000</price>
<publish-date>2007/10/02</publish-date>
</item>
</oracle>
<mySql>
<item>
<name>商品名</name>
<price>20000</price>
<publish-date>2007/10/02</publish-date>
</item>
</mySql>
<postgreSql>
<item>
<name>商品名</name>
<price>20000</price>
<publish-date>2007/10/02</publish-date>
</item>
</postgreSql>
</database>
</os>


こんな感じのが、扱いやすかった記憶があります。
XMLSchemaとかDTDも書きやすいしね。

まぁ、例題って感じで捕らえてみて下さい。

お気に入りの本は
http://item.rakuten.co.jp/book/1464935/
これでした。

[ メッセージ編集済み 編集者: るぱん 編集日時 2007-10-02 16:39 ]
yozuki
会議室デビュー日: 2007/10/01
投稿数: 3
投稿日時: 2007-10-02 17:58
解決いたしました。
るぱんさま、MMXさま、
非常に分かりやすく且つ詳細に、ありがとうございました。
ためになりました。
参考URLまで・・・熟読いたします。




1

スキルアップ/キャリアアップ(JOB@IT)