PHP DOM - 如何使用parent / children / child将xpath迭代到数组中?

时间:2016-10-13 16:09:05

标签: php dom xpath domxpath domparser

我是使用DOM和PHP的新手,需要一些帮助来找出迭代xpath到数组的解决方案。我在网上找到的例子提供的帮助很少。

这是我的XML文件中的字符串内容:

    <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.2-c004 1.136881, 2010/06/10-18:11:35        "> 
        <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> 
        <rdf:Description 
            rdf:about="" 
            xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/" 
            xmlns:dc="http://purl.org/dc/elements/1.1/" 
            xmlns:tiff="http://ns.adobe.com/tiff/1.0/" 
            xmlns:exif="http://ns.adobe.com/exif/1.0/" 
            xmlns:xmp="http://ns.adobe.com/xap/1.0/" 
            xmlns:aux="http://ns.adobe.com/exif/1.0/aux/" 
            xmlns:crs="http://ns.adobe.com/camera-raw-settings/1.0/" 
            xmlns:Iptc4xmpCore="http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/" 
            xmlns:xmpRights="http://ns.adobe.com/xap/1.0/rights/" 
            photoshop:LegacyIPTCDigest="B0D1E9B9CFC1C774E7277517B04970DC" 
            photoshop:ColorMode="3" 
            photoshop:ICCProfile="sRGB IEC61966-2.1" 
            photoshop:AuthorsPosition="Tester" 
            photoshop:Headline="Big City Landscape" 
            photoshop:CaptionWriter="Freelancer" 
            photoshop:DateCreated="2016-08-05T02:16Z" 
            photoshop:City="NA" 
            photoshop:State="NA" 
            photoshop:Country="NA" 
            photoshop:TransmissionReference="2323" 
            photoshop:Instructions="set to landscape" 
            photoshop:Credit="Photographor: FirstName lastname" 
            photoshop:Source="Smart Phone Photo" 
            tiff:Make="Motorola" 
            tiff:Model="MB865" 
            tiff:Orientation="1" 
            tiff:ImageWidth="3264" 
            tiff:ImageLength="1840" 
            tiff:PhotometricInterpretation="2" 
            tiff:SamplesPerPixel="3" 
            tiff:XResolution="72/1" 
            tiff:YResolution="72/1" 
            tiff:ResolutionUnit="2" 
            exif:ExifVersion="0220" 
            exif:ExposureTime="1/11" 
            exif:ShutterSpeedValue="3459432/1000000" 
            exif:FNumber="24/10" 
            exif:ApertureValue="2526069/1000000" 
            exif:ExposureProgram="0" 
            exif:BrightnessValue="0/1" 
            exif:ExposureBiasValue="0/10" 
            exif:MaxApertureValue="3/1" 
            exif:SubjectDistance="0/1" 
            exif:MeteringMode="1" 
            exif:LightSource="4" 
            exif:FocalLength="460/100" 
            exif:SceneType="1" 
            exif:CustomRendered="1" 
            exif:ExposureMode="0" 
            exif:WhiteBalance="0" 
            exif:SceneCaptureType="0" 
            exif:GainControl="256" 
            exif:Contrast="0" 
            exif:Saturation="0" 
            exif:Sharpness="0" 
            exif:SubjectDistanceRange="0" 
            exif:DigitalZoomRatio="65536/65535" 
            exif:PixelXDimension="3264" 
            exif:PixelYDimension="1840" 
            exif:ColorSpace="1" 
            xmp:ModifyDate="2016-02-22T09:22:39-05:00" 
            xmp:MetadataDate="2016-08-05T02:21:35-04:00" 
            aux:ApproximateFocusDistance="0/1" 
            crs:AlreadyApplied="True" 
            Iptc4xmpCore:IntellectualGenre="NA" 
            Iptc4xmpCore:Location="NA" 
            Iptc4xmpCore:CountryCode="NA"> 
            <dc:rights> 
                <rdf:Alt> 
                    <rdf:li xml:lang="x-default">Copyright FirstName lastname</rdf:li> 
                </rdf:Alt> 
            </dc:rights> 
            <dc:creator> 
                <rdf:Seq> 
                    <rdf:li>FirstName lastname</rdf:li> 
                </rdf:Seq> 
            </dc:creator> 
            <dc:description> 
                <rdf:Alt> 
                    <rdf:li xml:lang="x-default">Jurks on the move</rdf:li> 
                </rdf:Alt> 
            </dc:description> 
            <dc:subject> 
                <rdf:Bag> 
                    <rdf:li>New Jurks in Town</rdf:li> 
                </rdf:Bag> 
            </dc:subject> 
            <dc:title> 
                <rdf:Alt> 
                    <rdf:li xml:lang="x-default">Big City Jurks</rdf:li> 
                </rdf:Alt> 
            </dc:title> 
            <tiff:BitsPerSample> 
                <rdf:Seq> 
                    <rdf:li>8</rdf:li> 
                    <rdf:li>8</rdf:li> 
                    <rdf:li>8</rdf:li> 
                </rdf:Seq> 
            </tiff:BitsPerSample> 
            <exif:ISOSpeedRatings> 
                <rdf:Seq> 
                    <rdf:li>107</rdf:li> 
                </rdf:Seq> 
            </exif:ISOSpeedRatings> 
            <exif:Flash exif:Fired="True" exif:Return="0" exif:Mode="1" exif:Function="False" exif:RedEyeMode="False"/> 
            <Iptc4xmpCore:CreatorContactInfo 
            Iptc4xmpCore:CiAdrExtadr="" 
            Iptc4xmpCore:CiAdrCity="" 
            Iptc4xmpCore:CiAdrRegion="NY" 
            Iptc4xmpCore:CiAdrPcode="" 
            Iptc4xmpCore:CiAdrCtry="USA" 
            Iptc4xmpCore:CiTelWork="" 
            Iptc4xmpCore:CiEmailWork="you@yourwebsite.com" 
            Iptc4xmpCore:CiUrlWork="www.yourwebsite.com"/> 
            <Iptc4xmpCore:SubjectCode> 
                <rdf:Bag> 
                    <rdf:li>Jurks</rdf:li> 
                </rdf:Bag> 
            </Iptc4xmpCore:SubjectCode> 
            <Iptc4xmpCore:Scene> 
                <rdf:Bag> 
                    <rdf:li>Big City</rdf:li> 
                </rdf:Bag> 
            </Iptc4xmpCore:Scene> 
            <xmpRights:UsageTerms> 
                <rdf:Alt> 
                    <rdf:li xml:lang="x-default">Free to use</rdf:li> 
                </rdf:Alt> 
            </xmpRights:UsageTerms> 
        </rdf:Description> 
        </rdf:RDF> 
    </x:xmpmeta>                                                                                  

这就是我解决问题的方法。

    $__data = "xmp-cache-test.xml";

    $content = file_get_contents('xmp-cache-test.xml');

    if(preg_match("/(\<x\:xmpmeta.*?\>.*?\<\/x\:xmpmeta\>)/s", $content, $matches))
        $data = "<?xml version='1.0'?>\n" . $matches[1];

    $myXmlString = $data ;
    $myXmlFilename = $__data;

    $doc = new DOMDocument();
    $doc->loadXML($myXmlString);
    $doc->documentURI = $myXmlFilename;
    $xpath = new DOMXpath($doc);

    $xpath->registerNamespace('x', 'adobe:ns:meta/');
    $xpath->registerNamespace('xmp', 'http://ns.adobe.com/xap/1.0/');
    $xpath->registerNamespace("Iptc4xmpCore", "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/");
    $xpath->registerNamespace('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');

    $elements = $xpath->evaluate('//rdf:RDF/rdf:Description');
    $arr_xmp = iterator_to_array($elements);
    print_r($arr_xmp);

//打印结果:

    Array ( 
        [0] => DOMElement Object ( 
            [tagName] => rdf:Description 
            [schemaTypeInfo] => 
            [nodeName] => rdf:Description 
            [nodeValue] => Copyright FirstName lastname FirstName lastname Jurks on the move 
            New Jurks in Town Big City Jurks 8 8 8 107 Jurks Big City Free to use 
            [nodeType] => 1 
            [parentNode] => (object value omitted) 
            [childNodes] => (object value omitted) 
            [firstChild] => (object value omitted) 
            [lastChild] => (object value omitted) 
            [previousSibling] => (object value omitted) 
            [nextSibling] => (object value omitted) 
            [attributes] => (object value omitted) 
            [ownerDocument] => (object value omitted) 
            [namespaceURI] => http://www.w3.org/1999/02/22-rdf-syntax-ns# [prefix] => rdf 
            [localName] => Description 
            [baseURI] => xmp-cache-test.xml 
            [textContent] => Copyright FirstName lastname FirstName lastname Jurks on the move 
            New Jurks in Town Big City Jurks 8 8 8 107 Jurks Big City Free to use 
            ) ) 

上述结果并非我的预期。 我宁愿在数组中查看更像下面的例子 以及其他一些选择:

    Array ( 
        [rdf:about] => 
        [xmlns:photoshop] => http://ns.adobe.com/photoshop/1.0/ 
        [xmlns:dc] => http://purl.org/dc/elements/1.1/ 
        [xmlns:tiff] => http://ns.adobe.com/tiff/1.0/ 
        [xmlns:exif] => http://ns.adobe.com/exif/1.0/ 
        [xmlns:xmp] => http://ns.adobe.com/xap/1.0/ 
        [xmlns:aux] => http://ns.adobe.com/exif/1.0/aux/ 
        [xmlns:crs] => http://ns.adobe.com/camera-raw-settings/1.0/ 
        [xmlns:Iptc4xmpCore] => http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/ 
        [xmlns:xmpRights] => http://ns.adobe.com/xap/1.0/rights/ 
        [photoshop:LegacyIPTCDigest] => B0D1E9B9CFC1C774E7277517B04970DC 
        [photoshop:ColorMode] => 3 
        [photoshop:ICCProfile] => sRGB IEC61966-2.1 
        [photoshop:AuthorsPosition] => Tester 
        [photoshop:Headline] => Big City Landscape 
        [photoshop:CaptionWriter] => Freelancer 
        [photoshop:DateCreated] => 2016-08-05T02:16Z 
        [photoshop:City] => NA 
        [photoshop:City] => NA 
        [photoshop:State] => NA 
        [photoshop:Country] => NA 
        [photoshop:TransmissionReference] => 2323 
        [photoshop:Instructions] => set to landscape 
        [photoshop:Credit] => Photographor: FirstName lastname 
        [photoshop:Source] => Smart Phone Photo 
        [tiff:Make] => Motorola 
        [tiff:Model] => MB865 
        [tiff:Orientation] => 1 

        ------------ // continue
        )
  1. 选项:举个例子会很有帮助。

    1. 我应该如何使用DOM来创建数组呢?
    2. 如果我需要删除说&#34; tiff和exif&#34;从数组什么 方法应该是这样吗?
    3. 使用Dom更新说&#34; photoshop:Credit&#34;值。
    4. 如何使用DOM将数组反转回XML字符串。

1 个答案:

答案 0 :(得分:0)

============= EDIT ===================

xml to array部分,这里的问题几乎相同:What is the best php DOM 2 Array function?

我玩了一些代码,这就是结果:

function xml_to_array($root) {
    $result = array();

    if ($root->hasAttributes()) {
        $attrs = $root->attributes;
        foreach ($attrs as $attr) {
            $result['@attributes'][$attr->name] = $attr->value;
        }
    }

    if ($root->hasChildNodes()) {
        $children = $root->childNodes;
        if ($children->length == 1) {
            $child = $children->item(0);
            if ($child->nodeType == XML_TEXT_NODE) {
                $result['_value'] = $child->nodeValue;
                return count($result) == 1
                    ? $result['_value']
                    : $result;
            }
        }
        $groups = array();
        foreach ($children as $child) {
            if($child->nodeType == XML_TEXT_NODE && empty(trim($child->nodeValue))) continue;
            if (!isset($result[$child->nodeName])) {
                $result[$child->nodeName] = xml_to_array($child);
            } else {
                if (!isset($groups[$child->nodeName])) {
                    $result[$child->nodeName] = array($result[$child->nodeName]);
                    $groups[$child->nodeName] = 1;
                }
                $result[$child->nodeName][] = xml_to_array($child);
            }
        }
    }

    return $result;
}


// $content = your xml raw source

if(preg_match("/(\<x\:xmpmeta.*?\>.*?\<\/x\:xmpmeta\>)/s", $content, $matches))
    $data = "<?xml version='1.0'?>\n" . $matches[1];

$myXmlString = $data ;
//$myXmlFilename = $__data;

$doc = new DOMDocument();
$doc->loadXML($myXmlString);

$array = xml_to_array($doc);
print_r($array);

有人在那里写了非常简洁的函数,它遍历xml收集属性和节点值,并且几乎忽略了与可怕命名空间相关的痛苦。

如果您需要从数组中删除项目,只需使用unset,如:

unset($array['x:xmpmeta']['rdf:RDF']['rdf:Description']['tiff:BitsPerSample']);

至于如何更新属性值,请在此处完全相同的问题:Change tag attribute value with PHP DOMDocument

$dom = new DOMDocument();
$dom->loadHTML('<a href="http://foo.bar/">Click here</a>');

foreach ($dom->getElementsByTagName('a') as $item) {

    $item->setAttribute('href', 'http://google.com/');
    echo $dom->saveHTML();
    exit;
}

最后,如何从数组反向转向DOM:没有简单的方法,您必须手动创建DOM对象并逐个创建节点和属性。

填充后,您可以调用http://php.net/manual/en/domdocument.savexml.php来获取xml代码。

<?php

$doc = new DOMDocument('1.0');
// we want a nice output
$doc->formatOutput = true;

$root = $doc->createElement('book');
$root = $doc->appendChild($root);

$title = $doc->createElement('title');
$title = $root->appendChild($title);

$text = $doc->createTextNode('This is the title');
$text = $title->appendChild($text);

echo "Saving all the document:\n";
echo $doc->saveXML() . "\n";

echo "Saving only the title part:\n";
echo $doc->saveXML($title);

?>

希望这有帮助,