Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions Mf2/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,15 @@ function mfNamesFromClass($class, $prefix='h-') {
return $matches;
}

/**
* Registered with the XPath object and used within XPaths for finding root elements.
* @param string $class
* @return bool
*/
function classHasMf2RootClassname($class) {
return count(mfNamesFromClass($class, 'h-')) > 0;
}

/**
* Get Nested µf Property Name From Class
*
Expand Down Expand Up @@ -371,7 +380,10 @@ public function __construct($input, $url = null, $jsonMode = false) {
@$doc->loadHTML('');
}

// Create an XPath object and allow some PHP functions to be used within XPath queries.
$this->xpath = new DOMXPath($doc);
$this->xpath->registerNamespace('php', 'http://php.net/xpath');
$this->xpath->registerPhpFunctions('\\Mf2\\classHasMf2RootClassname');

$baseurl = $url;
foreach ($this->xpath->query('//base[@href]') as $base) {
Expand Down Expand Up @@ -1164,7 +1176,7 @@ public function parseH(\DOMElement $e, $is_backcompat = false, $has_nested_mf =
'type' => $mfTypes,
'properties' => $return
);

if(trim($e->getAttribute('id')) !== '') {
$parsed['id'] = trim($e->getAttribute("id"));
}
Expand Down Expand Up @@ -1506,7 +1518,7 @@ public function parseFromId($id, $convertClassic=true) {
public function getRootMF(DOMElement $context = null) {
// start with mf2 root class name xpath
$xpaths = array(
'contains(concat(" ",normalize-space(@class)), " h-")'
'(php:function("\\Mf2\\classHasMf2RootClassname", normalize-space(@class)))'
);

// add mf1 root class names
Expand Down Expand Up @@ -1687,15 +1699,9 @@ public function addMfClasses(DOMElement $el, $classes) {
*/
public function hasRootMf2(\DOMElement $el) {
$class = str_replace(array("\t", "\n"), ' ', $el->getAttribute('class'));
$classes = array_filter(explode(' ', $class));

foreach ( $classes as $classname ) {
if ( strpos($classname, 'h-') === 0 ) {
return true;
}
}

return false;
// Check for valid mf2 root classnames, not just any classname with a h- prefix.
return count(mfNamesFromClass($class, 'h-')) > 0;
}

/**
Expand Down
31 changes: 31 additions & 0 deletions tests/Mf2/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -860,5 +860,36 @@ public function testInvalidOrdinalDate() {
$this->assertEquals('2016-12-31', Mf2\normalizeOrdinalDate('2016-366'));
$this->assertEquals('', Mf2\normalizeOrdinalDate('2016-367'));
}

/**
* @see https://github.com/microformats/php-mf2/issues/230
*/
public function testPropertyWithInvalidHPrefixedRootClassParsed() {
$input = <<<EOF
<div class="h-card">
<img class="u-photo w-32 h-32" alt="Jon Doe" src="/image.jpg"/>
</div>
EOF;

$output = Mf2\parse($input);
$this->assertEquals(array('value' => '/image.jpg', 'alt' => 'Jon Doe'), $output['items'][0]['properties']['photo'][0]);
}

public function testGetRootMfOnlyFindsValidElements() {
$input = <<<EOF
<div class="h-entry>"> <a href="https://example.com" class="u-url">content</a></div>
<div class="h-entry1>"> <a href="https://example.com" class="u-url">content</a></div>
<div class="h-👍"> <a href="https://example.com" class="u-url">content</a></div>
<div class="h-hentry_"> <a href="https://example.com" class="u-url">content</a></div>
<div class="h-"> <a href="https://example.com" class="u-url">content</a></div>
<div class="h-vendor123-name"><a href="https://example.com" class="u-url">content</a></div>
EOF;

$p = new Mf2\Parser($input);
$rootEls = $p->getRootMF();

$this->assertEquals(1, count($rootEls));
$this->assertEquals('h-vendor123-name', $rootEls->item(0)->getAttribute('class'));
}
}