maoring blog

このブログはセマンティックウェブ関連の技術的なあれこれを綴ったブログです。

javascriptとmicrodata(調査中)その3

Live Microdataで利用しているJavaScriptを参考に,まずはmicrodataをきちんと切り出したいという要望を満たしたい。 今日は以下の3つのjavascriptをみてみるよん。

<script src="../jquery.microdata.js"></script>
<script src="../jquery.microdata.json.js"></script>
<script src="live.js"></script>

最初からクライマックス!というわけでlive.jsを見てみたけど,このウェブサイト特有の事情で使っているっぽいから とりあえず関係ないのではないかという適当な結論に。

次本題。jquery.microdata.js これが何を認識して何を返しているかということを知りたい。
コードを読んでみて自分が随分JavaScriptを知らないことが分かった…。

もとの呼び出しているhtmlから必要そうな部分だけ抜粋したものを掲載する。 これでも普通に動いてmicrodataから得られたタイプとプロパティを綺麗に構造化してJSONで出力してくれる。

<!doctype html>                                                                                                                         
<html>                                                                                                                                  
<head>                                                                                                                                  
<meta charset="utf-8">                                                                                                                  
<title>Live Microdata</title>                                                                                                           
<link rel="stylesheet" href="css/ui-lightness/jquery-ui-1.7.2.custom.css">                                                              
<link rel="stylesheet" href="live.css">                                                                                                 
<script src="../lib/jquery-1.6.4.min.js"></script>                                                                                      
<script src="../lib/jquery-ui-1.7.2.custom.min.js"></script>                                                                            
<script src="../lib/jquery.textarearesizer.compressed.js"></script>                                                                     
<script src="../lib/json2.js"></script>                                                                                                 
<script src="../jquery.microdata.js"></script>                                                                                          
<script src="../jquery.microdata.json.js"></script>                                                                                     
<script src="live.js"></script>                                                                                                         
<script>document.createElement('footer');</script>                                                                                      
</head>                                                                                                                                 
<body>                                                                                                                                  
                                                                                                                                        
<h1><a href=".">Live Microdata</a></h1>                                                                                                 
                                                                                                                                        
<form class="examples">                                                                                                                 
Examples:                                                                                                                               
<select title="Select an example to load it below...">                                                                                  
<option value=""></option>                                                                                                              
<option value="vcard-jack">vCard: Jack Bauer</option>                                                                                   
</select>                                                                                                                               
</form>                                                                                                                                 
                                                                                                                                        
<div class="warnings"></div>                                                                                                            
                                                                                                                                        
<textarea>Write HTML/Microdata markup here...</textarea>                                                                                
                                                                                                                                        
<div id="tabs">                                                                                                                         
  <ul>                                                                                                                                  
    <li><a href="#preview">Preview</a></li>                                                                                             
    <li><a href="#json" title="Microdata as JSON">JSON</a></li>                                                                         
  </ul>                                                                                                                                 
  <div id="preview"><iframe src="preview.html"></iframe></div>                                                                          
  <div id="json"></div>                                                                                                                 
</div>                                                                                                                                  
</body>                                                                                                                                 
</html> 

困った。何が困ったってエレガントすぎてどう呼び出して値をどう渡しているのか分からない… 部分的にでもjquery.microdata.jsがやっていることを理解したい。

'use strict';

(function(){
  var $ = jQuery;

  $.microdata = {};

  // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-time-string
  function validTimeStringLength(s) {
    var m = /^(\d\d):(\d\d)(:(\d\d)(\.\d+)?)?/.exec(s);
    if (m && m[1]<=23 && m[2]<=59 && (!m[4] || m[4]<=59))
      return m[0].length;
    return 0;
  }
…中略  
 $.fn.extend({
    items: document.getItems && t.itemType && t.itemType.contains ? function(types) {
      var doc = this[0];
      if (doc.getItems)
        return $(types ? doc.getItems(types) : doc.getItems());
      return getItems.call(this, types);
    } : getItems,
    itemScope: t.itemScope ? function() {
      return this[0].itemScope;
    } : function () {
      return this[0].getAttribute('itemscope') != null;
    },
    itemType: t.itemType && t.itemType.contains ? function() {
      return this[0].itemType;
    } : tokenList('itemtype'),
    itemId: t.itemId == 'id' ? function() {
      return this[0].itemId;
    } : function () {
      return resolve(this[0], 'itemid');
    },
    itemProp: t.itemProp && t.itemProp.contains ? function() {
      return this[0].itemProp;
    } : tokenList('itemprop'),
    itemRef: t.itemRef && t.itemRef.contains ? function() {
      return this[0].itemRef;
    } : tokenList('itemref'),
    itemValue: t.itemValue == t && t.value == 'value' ? function() {
      return this[0].itemValue;
    } : itemValue,
    properties: t.properties && t.properties.namedItem ? function(name) {
      return $(name ? this[0].properties.namedItem(name) : this[0].properties);
    } : properties
  });
})();

どうやら全体を即時関数にして,その後色々な読み取るための関数を定義し, $.fn.extendでjqueryを拡張して利用できるようにしているらしい。最後の拡張を上手いこと使えば htmlで埋め込まれているmicrodataを上手く取り出せるのではあるまいか…!?
その前にjQuery.fn.extendとはなんぞや。

jQuery日本語リファレンス jQuery does not mean Japanese Query...

jQuery.fn.extend(object)
jQueryエレメントに独自の新しいメソッドを追加する。(典型的なjQueryプラグインの作成方法)

まじか。サンプルも載っていた。

//jQueryオブジェクトに、新たに「全てチェック状態にする」「全て非チェック状態にする」メソッドを追加  
jQuery.fn.extend({
  check: function() {
    return this.each(function() { this.checked = true; });
  },
  uncheck: function() {
    return this.each(function() { this.checked = false; });
  }
});
$("input[@type=checkbox]").check();
$("input[@type=radio]").uncheck();

さて,本題に戻ろう。最終的なイメージはmicrodataの論文のマークアップがされているものがあったら,それを抽出してその要旨を 表示させること。そのためにまず,microdataの論文のマークアップを正しく抽出する必要がある。当然のことを言い過ぎているきらいがあるのは 気にしないでちょ。なので,jquery.microdata.jsとmicrodataの含まれているページを共存させて,jquery.microdata.jsさんに 以下の様なマークアップがあったら,それを綺麗に取り出してくれるようなものを作って欲しいのだ。

<span itemscope itemtype="http://schema.org/ScholarlyArticle">                                                                         
<p> Kanehisa M, et al. Nucleic Acids Res. 40, D109-D114 (2012).</p>                                                              
[<meta itemprop='entryID' content='pmid:22080510'/>                                                                                  
<a href="http://www.ncbi.nlm.nih.gov/pubmed/22080510">pubmed</a>]                                         
<div itemprop="name">Rojar</div>                                                                                                    
</span>                                                                                                                            

↑ここから itemtype(タイプ,語彙の種類)="http://schema.org/ScholarlyArticle"であり,itemprop(プロパティ,属性)='entryID' の content(中身)='pmid:22080510' をとっておくんなましというわけだ。

ヒントになりそうなhtmlを見つけた。
atoato88 / operate-microdata
ちょっと抜粋。

<head>
   <meta charset="UTF-8">
   <title>携帯電話連動型電子レンジ</title>
   <link rel="stylesheet" href="css/style.css" />
   <script type="text/javascript" src="js/jquery-1.4.4.min.js"></script>
   <script type="text/javascript" src="js/jquery.microdata.js"></script>
   <script type="text/javascript">
       $(function(){
           var r = $('article section section').properties().map(function(i, e){return $(e).itemValue();}).get();
           alert(r);
       });
   </script>
</head>
<body>
    <article itemscope itemtype="http://example.com/Thing">
        <section itemscope itemtype="http://example.com/Brand">
            <div itemprop="name">電話レンジ(仮)</div>
            <div itemprop="name">未来ガジェット8号機</div>
            <section itemscope itemtype="http://example.com/Design">
                <div itemprop="name">サイコロ型電子レンジ</div>
                                <div itemprop="description">
                    <p>斬新なサイコロ型デザイン。</p>
                    <p>レトロ調に仕上げました。</p>
                </div> 
            </section>
               </section>
       </article>
</body>
</html>

article タグの中の section タグの中の sectionタグの中のプロパティの中身をmapを使ってコンマ区切りに全て出力してくれる。

サイコロ型電子レンジ,斬新なサイコロ型デザイン。,レトロ調に仕上げました。

と表示してくれる。んー近い気がしてきた。ただこれだとhtmlタグの指定をしないといけない。
そうではなくて,itemtypeで指定したいのだ。んーどうすれば…!
発想の転換をしよう。今回はクローラーではないので網羅的である必要はない。だから,hoverされたらその時のタグ名を入手して(もしくはaタグにして)
itemtypeとitempropとコンテンツを取得出来れば良いのである。ということで三つ組ゲットだぜ!のコードを書いてみた。コードの下の画像のようにalertで取り出してくれる。
ここではspanタグの中身の最初のmicrodataの情報を取り出してちょというコードになっている。

<!DOCTYPE HTML>
<html lang="ja">
<head>
        <meta charset="UTF-8">                                                                                                          
        <title>Short Sample Code</title>                                                                                                
        <link rel="stylesheet" href="css/style.css" />                                                                                  
        <script type="text/javascript" src="js/jquery-1.6.4.min.js"></script>                                                           
        <script type="text/javascript" src="js/jquery.microdata.js"></script>                                                           
        <script type="text/javascript">                                                                                                 
        $(function(){
                triplearray = new Array(3);     
                triplearray[0] = $("span").itemType().toString();                                                                       
                triplearray[1] = $('span').properties().itemProp().toString();                                                          
                triplearray[2] = $('span').properties().itemValue().toString();                                                         
                alert("itemtype : " + triplearray[0] +"\nitemprop : " + triplearray[1] +"\nitemvalue : " +  triplearray[2]);
        });                                                                                                                             
        </script>
</head>
<body>
<span itemscope="sample" itemtype="http://schema.org/ScholarlyArticle">
<p> Kanehisa M, et al. Nucleic Acids Res. 40, D109-D114 (2012).</p>                                                                     
[<meta itemprop='entryID' content='pmid:22080510'/>
<a href="http://www.ncbi.nlm.nih.gov/pubmed/22080510">pubmed</a>]
</span>
</body>
</html>

f:id:maoring:20130612150901p:plain

ってアップしてみて驚いた。hatenaで写真をアップするとmicrodataを勝手に入れてくれるんだ!

コード起こすとこんな感じ。

<p>
 <span itemscope itemtype="http://schema.org/Photograph">
  <img src="http://cdn-ak.f.st-hatena.com/images/fotolife/m/maoring/20130612/20130612150901.png" alt="f:id:maoring:20130612150901p:plain" title="f:id:maoring:20130612150901p:plain" class="hatena-fotolife" itemprop="image">
</span>
</p>

itemtype="http://schema.org/Photograph"
itemprop="image"
img src="http://cdn-ak.f.st-hatena.com/images/fotolife/m/maoring/20130612/20130612150901.png"

JSONにするとこんな感じ

{ "items": [ { "type": [ "http://schema.org/Photograph" ],
"properties": { "image": [ "http://cdn-ak.f.st-hatena.com/images/fotolife/m/maoring/20130612/20130612150901.png" ] } } ] }

Hatena 素晴らしやー。(長くなったので続く…)