Skip to content

Commit aec9c12

Browse files
committed
Support multiple <rdf:Description> elements
1 parent 30ad2ec commit aec9c12

File tree

2 files changed

+64
-19
lines changed

2 files changed

+64
-19
lines changed

src/Metadata/Xmp.php

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ public static function fromFile($fileName)
158158
}
159159

160160
/**
161+
* Returns the first node (element or attribute) with the given field name and namespace.
162+
*
161163
* @param $field
162164
* @param $ns
163165
* @param bool $checkAttributes
@@ -166,14 +168,15 @@ public static function fromFile($fileName)
166168
*/
167169
private function getNode($field, $ns, $checkAttributes = true)
168170
{
169-
$rdfDesc = $this->getRDFDescription($ns);
170-
171171
// check for field as an element or an attribute
172172
$query = ($checkAttributes)? $field . '|@' . $field: $field;
173-
$result = $this->xpath->query($query, $rdfDesc);
174173

175-
if ($result->length) {
176-
return $result->item(0);
174+
$rdfDescriptions = $this->getRDFDescriptions($ns);
175+
foreach($rdfDescriptions as $rdfDesc) {
176+
$result = $this->xpath->query($query, $rdfDesc);
177+
if ($result->length) {
178+
return $result->item(0);
179+
}
177180
}
178181

179182
return null;
@@ -267,29 +270,28 @@ private function getSeq($field, $namespace)
267270

268271
return null;
269272
}
270-
271273
/**
274+
* Returns all `rdf:Description` elements with the given namespace.
275+
*
272276
* @param $namespace
273277
*
274-
* @return \DOMNode|null
278+
* @return array Array of \DOMNode
275279
*/
276-
private function getRDFDescription($namespace)
280+
private function getRDFDescriptions($namespace)
277281
{
278-
// element
279-
$description = $this->xpath->query("//rdf:Description[*[namespace-uri()='$namespace']]");
280-
281-
if ($description->length > 0) {
282-
return $description->item(0);
283-
}
282+
$result = [];
284283

285-
// attribute
286-
$description = $this->xpath->query("//rdf:Description[@*[namespace-uri()='$namespace']]");
284+
$element_query = "//rdf:Description[*[namespace-uri()='$namespace']]";
285+
$attribute_query = "//rdf:Description[@*[namespace-uri()='$namespace']]";
286+
foreach([$element_query, $attribute_query] as $query) {
287+
$description = $this->xpath->query($query);
287288

288-
if ($description->length > 0) {
289-
return $description->item(0);
289+
if ($description->length > 0) {
290+
$result = array_merge($result, iterator_to_array($description));
291+
}
290292
}
291293

292-
return null;
294+
return $result;
293295
}
294296

295297
/**

tests/Metadata/XmpTest.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,49 @@ public function testGetImageRegionFromImageResavedWithPhotoshop()
454454
);
455455
}
456456

457+
/**
458+
* @covers ::getImageRegions
459+
*
460+
* The RDF/XML structure might contain several instances of
461+
* <rdf:Description xmlns:Iptc4xmpExt="...">. This test validates that we
462+
* find the image regions even when they are not located in the first
463+
* <rdf:Description> element.
464+
*
465+
* See https://github.com/Frameright/php-image-metadata-parser/issues/25
466+
*/
467+
public function testGetImageRegionFromImageWithMultipleRdfDescriptions()
468+
{
469+
// FIXME This test is disabled because we need a corresponding test fixture.
470+
// See https://github.com/Frameright/php-image-metadata-parser/issues/25
471+
return true;
472+
473+
$jpeg = JPEG::fromFile(
474+
__DIR__ . '/../Fixtures/multipleRdfDesc.jpg');
475+
476+
$xmp = $jpeg->getXmp();
477+
478+
$expectedFirstRegion = new ImageRegion();
479+
$expectedFirstRegion->regionDefinitionId = 'definition-0dae7c70-f936-49ad-80d2-a9f0f6c0fcdb';
480+
$expectedFirstRegion->regionName = '1:1 Square (Common sizes)';
481+
$expectedFirstRegion->id = 'crop-0fd40a5b-ad5f-4b29-9ab2-43afc21b44a6';
482+
$expectedFirstRegion->names = null;
483+
$expectedFirstRegion->types = null;
484+
$expectedFirstRegion->roles = [
485+
'http://cv.iptc.org/newscodes/imageregionrole/cropping',
486+
];
487+
$expectedFirstRegion->rbShape = 'rectangle';
488+
$expectedFirstRegion->rbUnit = 'relative';
489+
$expectedFirstRegion->rbXY = new Point(0.11890472618154539, 0.13225);
490+
$expectedFirstRegion->rbRx = null;
491+
$expectedFirstRegion->rbH = '0.4785';
492+
$expectedFirstRegion->rbW = '0.7179294823705926';
493+
494+
$this->assertEquals(
495+
$expectedFirstRegion,
496+
$xmp->getImageRegions()[0]
497+
);
498+
}
499+
457500
/**
458501
* @param Xmp $xmp
459502
*/

0 commit comments

Comments
 (0)