From e5f1e28adac74ba9aa1a22b11e5c4a4d47af2e7b Mon Sep 17 00:00:00 2001 From: Dave Longley Date: Fri, 15 Feb 2013 12:16:26 -0500 Subject: [PATCH] Drop duplicates when creating node maps. --- jsonld-tests.php | 135 ++++++++++++++++++++++++++++++++++++----------- jsonld.php | 31 ++++++++--- 2 files changed, 128 insertions(+), 38 deletions(-) diff --git a/jsonld-tests.php b/jsonld-tests.php index ad53ce1..5666800 100644 --- a/jsonld-tests.php +++ b/jsonld-tests.php @@ -28,38 +28,94 @@ if(!$isCli) { set_error_handler('error_handler'); } -function deep_compare($expect, $result) { - if(is_array($expect)) { - if(!is_array($result)) { +function deep_compare($expect, $result) { + if(is_array($expect)) { + if(!is_array($result)) { + return false; + } + if(count($expect) !== count($result)) { + return false; + } + foreach($expect as $i => $v) { + if(!deep_compare($v, $result[$i])) { + return false; + } + } + return true; + } + + if(is_object($expect)) { + if(!is_object($result)) { + return false; + } + if(count(get_object_vars($expect)) !== count(get_object_vars($result))) { + return false; + } + foreach($expect as $k => $v) { + if(!property_exists($result, $k) || !deep_compare($v, $result->{$k})) { + return false; + } + } + return true; + } + + return $expect === $result; +} + +function expanded_compare($x, $y, $is_list=false) { + if($x === $y) { + return true; + } + if(gettype($x) !== gettype($y)) { + return false; + } + if(is_array($x)) { + if(!is_array($y) || count($x) !== count($y)) { return false; } - if(count($expect) !== count($result)) { + $rval = true; + if($is_list) { + // compare in order + for($i = 0; $rval && $i < count($x); ++$i) { + $rval = expanded_compare($x[$i], $y[$i], false); + } + } + else { + // compare in any order + $iso = array(); + for($i = 0; $rval && $i < count($x); ++$i) { + $rval = false; + for($j = 0; !$rval && $j < count($y); ++$j) { + if(!isset($iso[$j])) { + if(expanded_compare($x[$i], $y[$j], false)) { + $iso[$j] = $i; + $rval = true; + } + } + } + } + $rval = $rval && (count($iso) === count($x)); + } + return $rval; + } + if(is_object($x)) { + $x_keys = array_keys((array)$x); + $y_keys = array_keys((array)$y); + if(count($x_keys) !== count($y_keys)) { return false; } - foreach($expect as $i => $v) { - if(!deep_compare($v, $result[$i])) { + foreach($x_keys as $key) { + if(!property_exists($y, $key)) { + return false; + } + if(!expanded_compare($x->{$key}, $y->{$key}, $key === '@list')) { return false; } } return true; } - if(is_object($expect)) { - if(!is_object($result)) { - return false; - } - if(count(get_object_vars($expect)) !== count(get_object_vars($result))) { - return false; - } - foreach($expect as $k => $v) { - if(!property_exists($result, $k) || !deep_compare($v, $result->{$k})) { - return false; - } - } - return true; - } - - return $expect === $result; + return false; } /** @@ -173,14 +229,35 @@ class TestRunner { echo $line; } - public function check($test, $expect, $result, $compare_json) { + public function check($test, $expect, $result, $type) { global $eol; - $json_equal = true; - if($compare_json) { - $json_equal = (json_encode($expect) === json_encode($result)); + $compare_json = !in_array('jld:ToRDFTest', $type); + $relabel = in_array('jld:FlattenTest', $type); + $expanded = $relabel || in_array('jld:ExpandTest', $type); + if($relabel) { + $expect = jsonld_relabel_blank_nodes($expect); + $result = jsonld_relabel_blank_nodes($result); } - if($json_equal || deep_compare($expect, $result)) { + + $pass = false; + if($compare_json) { + $pass = (json_encode($expect) === json_encode($result)); + } + if(!$pass) { + $pass = deep_compare($expect, $result) || + ($expanded && expanded_compare($expect, $result, $relabel)); + } + if(!$pass && $relabel) { + echo "WARN tried normalization..."; + $expect_normalized = jsonld_normalize( + $expect, array('format' => 'application/nquads')); + $result_normalized = jsonld_normalize( + $result, array('format' => 'application/nquads')); + $pass = ($expect_normalized === $result_normalized); + } + + if($pass) { $this->passed += 1; echo "PASS$eol"; } @@ -261,7 +338,6 @@ class TestRunner { foreach($manifest->sequence as $test) { // read test input files $type = $test->{'@type'}; - $compare_json = true; $options = array( 'base' => 'http://json-ld.org/test-suite/tests/' . $test->input); @@ -316,7 +392,6 @@ class TestRunner { $test->expect = read_test_nquads($test->expect, $filepath); $options['format'] = 'application/nquads'; $result = jsonld_to_rdf($input, $options); - $compare_json = false; } else { echo "Skipping test \"{$test->name}\" of type: " . @@ -325,7 +400,7 @@ class TestRunner { } // check results - $this->check($test, $test->expect, $result, $compare_json); + $this->check($test, $test->expect, $result, $type); } catch(JsonLdException $e) { echo $eol . $e; diff --git a/jsonld.php b/jsonld.php index 2468416..b29dc14 100644 --- a/jsonld.php +++ b/jsonld.php @@ -162,6 +162,16 @@ function jsonld_to_rdf($input, $options=array()) { return $p->toRDF($input, $options); } +/** + * Relabels all blank nodes in the given JSON-LD input. + * + * @param mixed input the JSON-LD input. + */ +function jsonld_relabel_blank_nodes($input) { + $p = new JsonLdProcessor(); + return $p->_labelBlankNodes(new UniqueNamer('_:b'), $input); +} + /** JSON-LD shared in-memory cache. */ global $jsonld_cache; $jsonld_cache = new stdClass(); @@ -1905,7 +1915,8 @@ class JsonLdProcessor { // add copy of value for each property from property generator if(is_array($expanded_property)) { - $this->_labelBlankNodes($active_ctx->namer, $expanded_value); + $expanded_value = $this->_labelBlankNodes( + $active_ctx->namer, $expanded_value); foreach($expanded_property as $iri) { self::addValue( $rval, $iri, self::copy($expanded_value), @@ -2043,11 +2054,13 @@ class JsonLdProcessor { $this->_createNodeMap($input, $graphs, '@default', $namer); // add all non-default graphs to default graph - $default_graph = $graphs->{'@default'}; - foreach($graphs as $graph_name => $node_map) { + $default_graph = $graphs->{'@default'}; + $graph_names = array_keys((array)$graphs); + foreach($graph_names as $graph_name) { if($graph_name === '@default') { continue; - } + } + $node_map = $graphs->{$graph_name}; if(!property_exists($default_graph, $graph_name)) { $default_graph->{$graph_name} = (object)array( '@id' => $graph_name, '@graph' => array()); @@ -2706,7 +2719,7 @@ class JsonLdProcessor { * * @return mixed the element. */ - protected function _labelBlankNodes($namer, $element) { + public function _labelBlankNodes($namer, $element) { if(is_array($element)) { $length = count($element); for($i = 0; $i < $length; ++$i) { @@ -3018,7 +3031,7 @@ class JsonLdProcessor { // add reference and recurse self::addValue( $subject, $property, (object)array('@id' => $id), - array('propertyIsArray' => true)); + array('propertyIsArray' => true, 'allowDuplicate' => false)); $this->_createNodeMap($o, $graphs, $graph, $namer, $id, null); } // handle $list @@ -3028,13 +3041,15 @@ class JsonLdProcessor { $o->{'@list'}, $graphs, $graph, $namer, $name, $_list); $o = (object)array('@list' => (array)$_list); self::addValue( - $subject, $property, $o, array('propertyIsArray' => true)); + $subject, $property, $o, + array('propertyIsArray' => true, 'allowDuplicate' => false)); } // handle @value else { $this->_createNodeMap($o, $graphs, $graph, $namer, $name, null); self::addValue( - $subject, $property, $o, array('propertyIsArray' => true)); + $subject, $property, $o, + array('propertyIsArray' => true, 'allowDuplicate' => false)); } } }