0

属性に多くの情報を含む XML があります。ここに小さな例を示します。

<?xml version="1.0" encoding="UTF-8"?>
 <collection xmlns="http://www.loc.gov/MARC21/slim">
  <record>
    <leader>04170npc a22003613u 4500</leader>
    <controlfield tag="001">vtls003932502</controlfield>
    <controlfield tag="003">WlAbNL</controlfield>
    <datafield tag="035" ind1=" " ind2=" ">
        <subfield code="a">(WlAbNL)1002</subfield>
    </datafield>
    <datafield tag="040" ind1=" " ind2=" ">
        <subfield code="a">WlAbNL</subfield>
        <subfield code="b">eng</subfield>
        <subfield code="c">WlAbNL</subfield>
    </datafield>
    <datafield tag="245" ind1="0" ind2="0">
        <subfield code="a">Scott Blair Collection,</subfield>
        <subfield code="f">1910 -</subfield>
    </datafield>
    <datafield tag="653" ind1=" " ind2=" ">
        <subfield code="a">rheology</subfield>
    </datafield>
  </record>
  <record>
    <leader>04229npc a22005893u 4500</leader>
    <controlfield tag="001">vtls003932503</controlfield>
    <datafield tag="035" ind1=" " ind2=" ">
        <subfield code="a">(WlAbNL)1004</subfield>
    </datafield>
    <datafield tag="040" ind1=" " ind2=" ">
       <subfield code="a">WlAbNL</subfield>
       <subfield code="b">eng</subfield>
       <subfield code="c">WlAbNL</subfield>
    </datafield>
    <datafield tag="245" ind1="0" ind2="0">
       <subfield code="a">Celtic Collection,</subfield>
       <subfield code="f">17th century -</subfield>
    </datafield>
    <datafield tag="653" ind1=" " ind2=" ">
        <subfield code="a">Scottish Gaelic language</subfield>
    </datafield>
 </record>
</collection>

現在、ドキュメント全体をロードするphpスクリプトがあります

$xml = simplexml_load_file("Mapping_coll_wales.xml");
$records = $xml->record;

これにより、次のようなレコード配列が作成されます(これを1つのレコードに少し削減しました)

  SimpleXMLElement Object
(
[leader] => 04170npc a22003613u 4500
[controlfield] => Array
    (
        [0] => vtls003932502
        [1] => WlAbNL
    )
 [datafield] => Array
    (
        [0] => SimpleXMLElement Object
            (
                [@attributes] => Array
                    (
                        [tag] => 035
                        [ind1] =>  
                        [ind2] =>  
                    )

                [subfield] => (WlAbNL)1002
            )
        [1] => SimpleXMLElement Object
            (
                [@attributes] => Array
                    (
                        [tag] => 040
                        [ind1] =>  
                        [ind2] =>  
                    )

                [subfield] => Array
                    (
                        [0] => WlAbNL
                        [1] => eng
                        [2] => WlAbNL
                    )

            )

        [2] => SimpleXMLElement Object
            (
                [@attributes] => Array
                    (
                        [tag] => 245
                        [ind1] => 0
                        [ind2] => 0
                    )

                [subfield] => Array
                    (
                        [0] => Scott Blair Collection,
                        [1] => 1910 -
                    )
            )
        [3] => SimpleXMLElement Object
            (
                [@attributes] => Array
                    (
                        [tag] => 653
                        [ind1] =>  
                        [ind2] =>  
                    )

                [subfield] => rheology
            )
    )

)

現在、配列内のどこにあるかを推測して必要なフィールドを取得し、各レコードをループしています (約 500 あります)。

for ($i =0; $i <5; $i++) {

echo '<strong>Title</strong> = : ' . $records[$i]->datafield[2]->subfield . '<br />';
echo '<strong>tag</strong>  = :' . $records[$i]->datafield[3]->subfield . '<br />';


echo '<br />------------------------------------------------------------------------<br />';
}

ただし、xml に他のタグが含まれている可能性があるため、インデックス 2 などのサブフィールドであることに依存したくありません。理想的には、次のようなものを使用して呼び出すことができるようにしたいと考えています。

echo '<strong>Title</strong> = : ' . $records[$i]->datafield[245][a] . '<br />';

それはかなり簡単で、何かが欠けているだけだと確信していますが、タグを配列インデックスとしてロードするか、タグでデータフィールドとコードでサブフィールドを直接取得する方法があるとよいでしょう。変化する。

それが理にかなっていることを願っています。

ポール

4

1 に答える 1

1

XPath を使用して、特定の条件を満たす要素を一致させることができます。

xpath()ただし、名前空間付きのノードを使用しているため、名前空間付きのパス式で使用する各ノードに名前空間を登録する必要があります。

ループで動作する以下の例を参照してください。

$nsp = 'marc';
$nsuri = 'http://www.loc.gov/MARC21/slim';


$records = $xml->record;


foreach($records as $record) {
    $record->registerXPathNamespace($nsp, $nsuri);
    $datafields = $record->xpath('marc:datafield[@tag=245]');
    foreach ($datafields as $datafield) {
        $datafield->registerXPathNamespace($nsp, $nsuri);
        $subfields = $datafield->xpath('marc:subfield[@code="a"]');
        var_dump($subfields);
    }
}

または、simplexml オブジェクト アクセスの代わりに xpath のみを使用して下向きに再帰することもできます。同じ結果が得られる 2 つの方法を次に示します。

$records = $xml->record;
$records->registerXPathNamespace($nsp, $nsuri);

$tags = array('245', '653');
$codes = array('a', 'f');

// METHOD 1: run an xpath for each tag/code combination
$desiredfields = array();
foreach ($tags as $tag) {
    $desiredsubfields = array();
    foreach($codes as $code) {
        $subfields = $records->xpath("marc:datafield[@tag='$tag']/marc:subfield[@code='$code']");
        $desiredsubfields[$code] = (string) $subfields[0];
    }
    $desiredfields[$tag] = $desiredsubfields;
}

var_export($desiredfields);

// METHOD 2: create a single xpath expression that matches every subfield you want
// Then visit each subfield retrieving tag from parent
$tagexpr = implode(' or ', array_map(function($t){return "@tag='{$t}'";}, $tags));
$codeexpr = implode(' or ', array_map(function($c){return "@code='{$c}'";}, $codes));
$xpath = "marc:datafield[{$tagexpr}]/marc:subfield[{$codeexpr}]";

$desiredfields = array();
$subfields = $records->xpath($xpath);

foreach ($subfields as $subfield) {
    $datafield = $subfield->xpath('..');
    $datafieldcode = (string) $datafield[0]['tag'];
    $desiredfields[$datafieldcode][(string) $subfield['code']] = (string) $subfield;
}

var_export($desiredfields);
于 2012-07-05T16:47:19.510 に答える