メモの日々


2008年03月06日(木) [長年日記]

  • NTTコミュニケーションズから葉書が来ていて、電話番号が変わったらNTTコミュニケーションズにも連絡してくれと書いてあった。でも理由が書かれていない。電話する必要はなさそうに思う。

[dev][web] XPathを使う

XPathを使う必要がある。XPathは過去に何度か勉強したがすぐに忘れてしまい身に付かない。身に付かないのはメモしないからなので、今回はメモする。

RubyのREXMLを使って次のスクリプトを書いた。

#!/usr/bin/ruby
require "rexml/document"

xml = <<EOF
<root>
  <momo>
    <buka>
      <name>hideyoshi</name>
      <type>saru</type>
      <weapon>panchi</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
  </momo>
  <momo>
    <buka>
      <name>taro</name>
      <type>inu</type>
      <weapon>kick</weapon>
    </buka>
  </momo>
  <momo>
    <buka>
      <name>jiro</name>
      <type>inu</type>
      <weapon>kick</weapon>
      <weapon>kick</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
  </momo>
  <momo>
    <buka>
      <name>otosan</name>
      <type>inu</type>
      <weapon>kick</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
  </momo>
  <momo>
    <buka>
      <name>unknown</name>
      <type>kiji</type>
      <weapon>tutuki</weapon>
      <weapon>tutuki</weapon>
      <weapon>tutuki</weapon>
      <weapon>tutuki</weapon>
    </buka>
  </momo>
</root>
EOF

doc = REXML::Document.new(xml)

xpaths = [
  ["/root/momo/buka/type", "/root/momo/buka/type"],
  ["//buka", "buka全て"],
  ["//type", "type全て"],
  ["//type/text()", "typeの内容全て"],
  ["//type[text()='inu']", "内容がinuのtype全て"],
  ["//momo[buka/type/text()='inu']", "内容がinuのtypeを持つmomo全て"],
  ["//momo[buka[type/text()='inu']]", "これでもいいみたい"],
  ["//momo[buka[type/text()='inu'][count(weapon)>=4]]",
   "内容がinuのtypeを持ち、weaponの数が4つ以上のmomo全て"],
  ["//momo[buka[type/text()='inu'][count(weapon[text()='kamituki'])>=3]]",
   "内容がinuのtypeを持ち、内容がkamitukiのweaponの数が4つ以上のmomo全て"],
  ["//momo[buka[type/text()='inu' and count(weapon[text()='kamituki'])>=3]]",
   "それともこう書くのかな"],
  ["//*[local-name()='momo']" +
      "[*[" +
          "[*[local-name()='type'][text()='inu']]" +
          "[count(*[local-name()='weapon'][text()='kamituki'])>=3]" +
      "]]",
   "訳あってlocal-nameだけを使って頑張って書く。合っているかわからん。"],
]

xpaths.each {|x, text|
  puts "-" * 40
  puts text
  puts "XPath: #{x}"
  puts "-" * 40
  puts REXML::XPath.match(doc, x)
  puts
}

実行結果は次の通り。

----------------------------------------
/root/momo/buka/type
XPath: /root/momo/buka/type
----------------------------------------
<type>saru</type>
<type>inu</type>
<type>inu</type>
<type>inu</type>
<type>kiji</type>

----------------------------------------
buka全て
XPath: //buka
----------------------------------------
<buka>
      <name>hideyoshi</name>
      <type>saru</type>
      <weapon>panchi</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
<buka>
      <name>taro</name>
      <type>inu</type>
      <weapon>kick</weapon>
    </buka>
<buka>
      <name>jiro</name>
      <type>inu</type>
      <weapon>kick</weapon>
      <weapon>kick</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
<buka>
      <name>otosan</name>
      <type>inu</type>
      <weapon>kick</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
<buka>
      <name>unknown</name>
      <type>kiji</type>
      <weapon>tutuki</weapon>
      <weapon>tutuki</weapon>
      <weapon>tutuki</weapon>
      <weapon>tutuki</weapon>
    </buka>

----------------------------------------
type全て
XPath: //type
----------------------------------------
<type>saru</type>
<type>inu</type>
<type>inu</type>
<type>inu</type>
<type>kiji</type>

----------------------------------------
typeの内容全て
XPath: //type/text()
----------------------------------------
saru
inu
inu
inu
kiji

----------------------------------------
内容がinuのtype全て
XPath: //type[text()='inu']
----------------------------------------
<type>inu</type>
<type>inu</type>
<type>inu</type>

----------------------------------------
内容がinuのtypeを持つmomo全て
XPath: //momo[buka/type/text()='inu']
----------------------------------------
<momo>
    <buka>
      <name>taro</name>
      <type>inu</type>
      <weapon>kick</weapon>
    </buka>
  </momo>
<momo>
    <buka>
      <name>jiro</name>
      <type>inu</type>
      <weapon>kick</weapon>
      <weapon>kick</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
  </momo>
<momo>
    <buka>
      <name>otosan</name>
      <type>inu</type>
      <weapon>kick</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
  </momo>

----------------------------------------
これでもいいみたい
XPath: //momo[buka[type/text()='inu']]
----------------------------------------
<momo>
    <buka>
      <name>taro</name>
      <type>inu</type>
      <weapon>kick</weapon>
    </buka>
  </momo>
<momo>
    <buka>
      <name>jiro</name>
      <type>inu</type>
      <weapon>kick</weapon>
      <weapon>kick</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
  </momo>
<momo>
    <buka>
      <name>otosan</name>
      <type>inu</type>
      <weapon>kick</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
  </momo>

----------------------------------------
内容がinuのtypeを持ち、weaponの数が4つ以上のmomo全て
XPath: //momo[buka[type/text()='inu'][count(weapon)>=4]]
----------------------------------------
<momo>
    <buka>
      <name>jiro</name>
      <type>inu</type>
      <weapon>kick</weapon>
      <weapon>kick</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
  </momo>
<momo>
    <buka>
      <name>otosan</name>
      <type>inu</type>
      <weapon>kick</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
  </momo>

----------------------------------------
内容がinuのtypeを持ち、内容がkamitukiのweaponの数が4つ以上のmomo全て
XPath: //momo[buka[type/text()='inu'][count(weapon[text()='kamituki'])>=3]]
----------------------------------------
<momo>
    <buka>
      <name>otosan</name>
      <type>inu</type>
      <weapon>kick</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
  </momo>

----------------------------------------
それともこう書くのかな
XPath: //momo[buka[type/text()='inu' and count(weapon[text()='kamituki'])>=3]]
----------------------------------------
<momo>
    <buka>
      <name>otosan</name>
      <type>inu</type>
      <weapon>kick</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
  </momo>

----------------------------------------
訳あってlocal-nameだけを使って頑張って書く。合っているかわからん。
XPath: //*[local-name()='momo'][*[[*[local-name()='type'][text()='inu']][count(*[local-name()='weapon'][text()='kamituki'])>=3]]]
----------------------------------------
<momo>
    <buka>
      <name>otosan</name>
      <type>inu</type>
      <weapon>kick</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
      <weapon>kamituki</weapon>
    </buka>
  </momo>

本当は名前空間も使う必要があって、その場合はまだよくわかってない。REXMLは名前空間をきちんと扱えないらしいしな。

参考

やること

  • クレジットカード
  • 新税務署
  • ダンボール