2011-02-22 15 views
1

私はSimpleXMLを使用してXML Webサービスの応答からデータを取得しています。これらの部分を使ってデータベースレコードを作成する必要があります。ここで私の問題です:このXMLは(私の心では、とにかく)非常に奇妙な構造であり、私は一緒に単一のレコードを構成する必要があるすべての部分を取得する方法がわかりません。これは、National Weather Serviceの予測Webサービスから返されるデータです。複数の緯度/経度ペア、開始日、終了日を渡して、風速、風向、波高の3つのデータを返すように求めています。それが返すものは、緯度/経度のペアごとに2つの別個の位置要素です.1つは風情報用、もう1つは水(波)情報用です。次に、位置要素の外側には、特定の位置に「適用可能」としてリストされたパラメータ要素がある。ここにサンプルがあります(申し訳ありません、それはとても長いのです。それは、ファイルが構成されているかを示すために種類の必要です。)私は何で終わる必要があることは、このようになりますそれぞれの場所のための3つのSQL INSERT文でこのXMLファイルの個々の要素を解析する方法は?

<data> 
    <location> 
     <location-key>point1</location-key> 
     <point latitude="38.99" longitude="-77.02"/> 
    </location> 

    <location> 
     <location-key>point2</location-key> 
     <point latitude="39.70" longitude="-104.80"/> 
    </location> 

    <location> 
     <location-key>point3</location-key> 
     <point latitude="47.60" longitude="-122.30"/> 
    </location> 

    <time-layout time-coordinate="local" summarization="none"> 
     <layout-key>k-p3h-n34-1</layout-key> 
     <start-valid-time>2011-02-22T16:00:00-05:00</start-valid-time> 
     <start-valid-time>2011-02-22T19:00:00-05:00</start-valid-time> 
    </time-layout> 

    <time-layout time-coordinate="local" summarization="none"> 
     <layout-key>k-p6h-n17-2</layout-key> 
     <start-valid-time>2011-02-22T19:00:00-05:00</start-valid-time> 
     <start-valid-time>2011-02-23T01:00:00-05:00</start-valid-time> 
    </time-layout> 

    <time-layout time-coordinate="local" summarization="none"> 
     <layout-key>k-p3h-n34-3</layout-key> 
     <start-valid-time>2011-02-22T14:00:00-07:00</start-valid-time> 
     <start-valid-time>2011-02-22T17:00:00-07:00</start-valid-time> 
    </time-layout> 

    <time-layout time-coordinate="local" summarization="none"> 
     <layout-key>k-p6h-n17-4</layout-key> 
     <start-valid-time>2011-02-22T17:00:00-07:00</start-valid-time> 
     <start-valid-time>2011-02-22T23:00:00-07:00</start-valid-time> 
    </time-layout> 

    <time-layout time-coordinate="local" summarization="none"> 
     <layout-key>k-p3h-n34-5</layout-key> 
     <start-valid-time>2011-02-22T13:00:00-08:00</start-valid-time> 
     <start-valid-time>2011-02-22T16:00:00-08:00</start-valid-time> 
    </time-layout> 

    <time-layout time-coordinate="local" summarization="none"> 
     <layout-key>k-p6h-n17-6</layout-key> 
     <start-valid-time>2011-02-22T16:00:00-08:00</start-valid-time> 
     <start-valid-time>2011-02-22T22:00:00-08:00</start-valid-time> 
    </time-layout> 

    <parameters applicable-location="point1"> 
     <wind-speed type="sustained" units="knots" time-layout="k-p3h-n34-1"> 
     <name>Wind Speed</name> 
     <value>5</value> 
     <value>5</value> 
     </wind-speed> 

     <direction type="wind" units="degrees true" time-layout="k-p3h-n34-1"> 
     <name>Wind Direction</name> 
     <value>340</value> 
     <value>350</value> 
     </direction> 

     <water-state time-layout="k-p6h-n17-2"> 
     <waves type="significant" units="feet"> 
      <name>Wave Height</name> 
      <value xsi:nil="true"/> 
      <value xsi:nil="true"/> 
     </waves> 
     </water-state> 

    </parameters> 

    <parameters applicable-location="point2"> 
     <wind-speed type="sustained" units="knots" time-layout="k-p3h-n34-3"> 
     <name>Wind Speed</name> 
     <value>4</value> 
     <value>2</value> 
     </wind-speed> 
     <direction type="wind" units="degrees true" time-layout="k-p3h-n34-3"> 
     <name>Wind Direction</name> 
     <value>180</value> 
     <value>200</value> 
     </direction> 
     <water-state time-layout="k-p6h-n17-4"> 
     <waves type="significant" units="feet"> 
      <name>Wave Height</name> 
      <value xsi:nil="true"/> 
     </waves> 
     </water-state> 
    </parameters> 
    <parameters applicable-location="point3"> 
     <wind-speed type="sustained" units="knots" time-layout="k-p3h-n34-5"> 
     <name>Wind Speed</name> 
     <value>7</value> 
     <value>8</value> 
     </wind-speed> 
     <direction type="wind" units="degrees true" time-layout="k-p3h-n34-5"> 
     <name>Wind Direction</name> 
     <value>290</value> 
     </direction> 
     <water-state time-layout="k-p6h-n17-6"> 
     <waves type="significant" units="feet"> 
      <name>Wave Height</name> 
      <value xsi:nil="true"/> 
     </waves> 
     </water-state> 
    </parameters> 
    </data> 

INSERT into gl_weather_data (weather_lat, weather_long, weather_time, weather_type, weather_value, weather_unit) values ("46.72", "-91.82", "2011-02-22T12:00:00-06:00", "Wind Speed", "9", "knots") 

INSERT into gl_weather_data (weather_lat, weather_long, weather_time, weather_type, weather_value, weather_unit) values ("46.72", "-91.82", "2011-02-22T12:00:00-06:00", "Wind Direction", "120", "degrees true") 

INSERT into gl_weather_data (weather_lat, weather_long, weather_time, weather_type, weather_value, weather_unit) values ("46.72", "-91.82", "2011-02-22T12:00:00-06:00", "Wave Height", "2", "feet") 

緯度/経度/時間は、これらの要素から来て、3つのすべてのインサートに共通しているであろうためのデータ:

<location> 
    <location-key>point1</location-key> 
    <point latitude="46.72" longitude="-91.82" /> 
</location> 

<time-layout time-coordinate="local" summarization="none"> 
    <layout-key>k-p3h-n34-1</layout-key> 
    <!-- note there can be more than one start-valid-time elements; we only want the first one --> 
    <start-valid-time>2011-02-22T16:00:00-05:00</start-valid-time> 
    <start-valid-time>2011-02-22T19:00:00-05:00</start-valid-time> 
</time-layout> 

タイプ、値、及び単位のデータが差分から来我々が取得している情報の種類に応じて、erent要素:

<!-- wind speed; need to get "knots" out of the wind-speed element's unit param, 
    "Wind Speed" out of the name element, and "5" out of the value element 
    (note there can be more than one value element; we only want the first) --> 
<parameters applicable-location="point1"> 
    <wind-speed type="sustained" units="knots" time-layout="k-p3h-n34-1"> 
    <name>Wind Speed</name> 
     <value>5</value> 
     <value>5</value> 
    </wind-speed> 

<!-- wind direction; need to get "degrees true" out of the direction element's unit param, 
    "Wind Direction" out of the name element, and "340" out of the value element 
    (note there can be more than one value element; we only want the first) --> 
<direction type="wind" units="degrees true" time-layout="k-p3h-n34-1"> 
     <name>Wind Direction</name> 
     <value>340</value> 
     <value>350</value> 
     </direction> 

<!-- wave height; need to get "feet" out of the waves element's unit param, 
    "Wave Height" out of the name element, and "13" out of the value element 
    (note there can be more than one value element; we only want the first) --> 
<water-state time-layout="k-p6h-n17-2"> 
     <waves type="significant" units="feet"> 
      <name>Wave Height</name> 
      <value>13</value> 
      <value xsi:nil="true"/> 
     </waves> 
     </water-state> 

私の主な混乱は、それに対応するパラメータの要素と場所の要素を関連付ける方法です。スキーマを書いたのであれば、パラメータを場所の子にしていたかもしれませんが、それはどういうものなのでしょうか?簡単には変更できません。

私はおそらく、位置要素のfor-eachを実行し、最初の位置キーを取得し、次にその位置キーを使用して、適切なパラメータ要素を選択するために、私はSimpleXMLでこれをどうやって行うのか分かりません。誰でもここで私を助けることができますか?

$dwml = simplexml_load_string($result); 
foreach ($dwml->data->parameters as $r) { 
    $locName = $r->direction['type']; 
    echo "Name: $locName<br />"; 
} 

foreach ($dwml->data->location as $r) { 
    echo "location key: " . $r->{'location-key'} . "<br />"; 
} 

これは」doesnの:それは私が何をする必要があるかにほど遠いませんが、少なくとも私は結果を得る - これは動作します

WORKING/NON-WORKINGコードを追加するように編集

トンの仕事:

$data = simplexml_load_string($result); 
    $all_locations = $data->xpath('location'); 
    foreach($all_locations as $location) { 
     list($location_key) = $location->xpath('location-key[1]'); 

     $params = $data->xpath("parameters[@applicable-location='{$location_key}']/*"); 
     foreach($params as $param) { 
      list($time) = $data->xpath("time-layout[layout-key='{$param['time-layout']}']/start-valid-time[1]"); 
      if($param->getName() == 'water-state') { 
      $param = $param->waves; 
      } 
      $sql = "INSERT into gl_weather_data values ('{$location->point['latitude']}', '{$location->point['longitude']}', '{$time}', '{$param->name}', '{$param->value[0]}', '{$param['units']}')"; 
      echo "{$sql}\n\n"; 
     } 
    } 

EDITED AGAIN OK、私はそれを得たと思います

$dwml = simplexml_load_string($result); 
    $all_locations = $dwml->data->xpath('location'); 
    foreach($all_locations as $location) { 
     list($location_key) = $location->xpath('location-key[1]'); 

     $params = $dwml->data->xpath("parameters[@applicable-location='{$location_key}']/*"); 
     foreach($params as $param) { 
      list($time) = $dwml->data->xpath("time-layout[layout-key='{$param['time-layout']}']/start-valid-time[1]"); 
      if($param->getName() == 'water-state') { 
      $param = $param->waves; 
      } 
      $sql = "INSERT into gl_weather_data values ('{$location->point['latitude']}', '{$location->point['longitude']}', '{$time}', '{$param->name}', '{$param->value[0]}', '{$param['units']}')"; 
      echo "{$sql}\n\n"; 
     } 
    } 
+0

かなりXMLではありません。あなたは私の同情を持っています。 – drudge

+0

ええ、同僚は、政府機関によって作成された無料のサービスから期待できることはほとんどないとコメントしました! – EmmyS

+0

実際、それは[完全に正規化されたデータ構造](http://en.wikipedia.org/wiki/Database_normalization)です。これは一般的にXML設計とデータベース設計においては良いことと考えられています。ノーマライゼーションは、様々なエンティティ間の関係を、それらの関係上の任意のクエリおよび/または変換を簡単かつ効率的にする方法で公開します。あなたはちょうど適切なツールを使用する必要があります。 PHPのXMLの場合、適切なツールは[XPath](http://php.net/manual/en/simplexmlelement.xpath.php)です。 – Lee

答えて

2

私はあなたがSimpleXML's XPath機能を使用することを示唆している: - ここ(dwmlが実際にルート要素、データではない)、実際に私のためにどのような作品です。

$data = new SimpleXMLElement($string); 

$all_locations = $data->xpath('location'); 
foreach($all_locations as $location) { 
    list($location_key) = $location->xpath('location-key[1]'); 

    $params = $data->xpath("parameters[@applicable-location='{$location_key}']/*"); 
    foreach($params as $param) { 
     list($time) = $data->xpath("time-layout[layout-key='{$param['time-layout']}']/start-valid-time[1]"); 
     if($param->getName() == 'water-state') { 
     $param = $param->waves; 
     } 
     $sql = "INSERT into gl_weather_data values ('{$location->point['latitude']}', '{$location->point['longitude']}', '{$time}', '{$param->name}', '{$param->value[0]}', '{$param['units']}')"; 
     echo "{$sql}\n\n"; 
    } 
} 

編集すべて<location>の要素のためのクエリ上記の例では、その後、それぞれに行く<parameters>セクションを見つけ

あなたはこのようなものになってしまいますロケーション。あなたはそれを他の方法に近づけることを好むかもしれないということが私にはあります。<parameters>の要素をすべて見つけてから、関連する<location>を探してください。 XPathを使用し

、この変化は非常に簡単です:

$data = new SimpleXMLElement($string); 
$all_params = $data->xpath("parameters"); 
foreach($all_params as $paramblock) { 
    list($location) = $data->xpath("location[location-key='{$paramblock['applicable-location']}']"); 

    foreach($paramblock->children() as $item) { 
     list($time) = $data->xpath("time-layout[layout-key='{$item['time-layout']}']/start-valid-time[1]"); 
     if($item->getName() == 'water-state') { 
     $item = $item->waves; 
     } 
     $sql = "INSERT into gl_weather_data values ('{$location->point['latitude']}', '{$location->point['longitude']}', '{$time}', '{$item->name}', '{$item->value[0]}', '{$item['units']}')"; 
     echo "{$sql}\n\n"; 
    } 
} 
+0

ありがとう、私は何をする必要があるように見えます。しかし、(Simplexml_load_string($ result)とは対照的に)新しいSimpleXMLElement($ result)を使用するたびに何らかの理由で空白のページが表示されますが、目に見えるエラーはありませんが、ビューソースまたは実際のページには何も表示されません。 – EmmyS

+0

[関数simplexml_load_string()](http://www.php.net/manual/en/functionsimplexml-load-string.php)、[SimpleXMLElementコンストラクタ](http://www.php.net /manual/en/simplexmlelement.construct.php)両方とも[SimpleXMLElement](http://www.php.net/manual/en/class.simplexmlelement.php)のオブジェクトインスタンスを返します。だからどちらのアプローチを使用しても、最終結果は同じです。なぜそれがあなたのために失敗しているのか分かりません。開発サーバーで[display_startup_errors](http://www.php.net/manual/en/errorfunc.configuration.php#ini.display-startup-errors)が有効になっていることを確認してください。 – Lee

+0

OK、問題を引き起こしているのはSimpleXMLElementだけではありません。私はこれまでに何が動作し、何が動作しないかを示すためにOPにコードを追加しています。私は非常に混乱しています。 – EmmyS

関連する問題