From 4d666a3f545b9cc6145f29ed38fd647cb2f88a66 Mon Sep 17 00:00:00 2001 From: Sergei Mikhailov Date: Wed, 11 Aug 2021 00:47:23 +0200 Subject: [PATCH 1/5] fix: export the RDF namespaced properties dynamically as XML namespaces and nodes --- core/kernel/impl/class.ApiModelOO.php | 109 ++++++++++---------------- 1 file changed, 41 insertions(+), 68 deletions(-) diff --git a/core/kernel/impl/class.ApiModelOO.php b/core/kernel/impl/class.ApiModelOO.php index d1d3145dc..754bc0587 100644 --- a/core/kernel/impl/class.ApiModelOO.php +++ b/core/kernel/impl/class.ApiModelOO.php @@ -90,37 +90,24 @@ public function importXmlRdf($targetNameSpace, $fileLocation) */ public function getResourceDescriptionXML($uriResource) { - $returnValue = (string) ''; - - - - - $dbWrapper = core_kernel_classes_DbWrapper::singleton(); $subject = $dbWrapper->quote($uriResource); - $baseNs = [ - 'xmlns:rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', - 'xmlns:rdfs' => 'http://www.w3.org/2000/01/rdf-schema#' - ]; + $namespaceCounter = core_kernel_persistence_smoothsql_SmoothModel::DEFAULT_WRITABLE_MODEL; - $modelId = core_kernel_persistence_smoothsql_SmoothModel::DEFAULT_WRITABLE_MODEL; - $modelUri = LOCAL_NAMESPACE . '#'; - - $currentNs = ["xmlns:ns{$modelId}" => $modelUri]; - $currentNs = array_merge($baseNs, $currentNs); - - - $allNs = $currentNs; - $allNs['xmlns:ns' . core_kernel_persistence_smoothsql_SmoothModel::DEFAULT_READ_ONLY_MODEL] = $modelUri; + $namespaces = [ + 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' => 'rdf', + 'http://www.w3.org/2000/01/rdf-schema#' => 'rdfs', + ROOT_URL . '#' => "ns{$namespaceCounter}", + ]; try { $dom = new DOMDocument(); $dom->formatOutput = true; $root = $dom->createElement('rdf:RDF'); - foreach ($currentNs as $namespaceId => $namespaceUri) { - $root->setAttribute($namespaceId, $namespaceUri); + foreach ($namespaces as $namespace => $namespaceId) { + $root->setAttribute("xmlns:$namespaceId", $namespace); } $dom->appendChild($root); @@ -133,58 +120,44 @@ public function getResourceDescriptionXML($uriResource) $object = trim($row['object']); $lang = trim($row['l_language']); - $nodeName = null; + if (strpos($predicate, '#') === false) { + continue; + } - foreach ($allNs as $namespaceId => $namespaceUri) { - if ($namespaceId === 'xml:base') { - continue; - } - if (preg_match("/^" . preg_quote($namespaceUri, '/') . "/", $predicate)) { - if (!array_key_exists($namespaceId, $currentNs)) { - $currentNs[$namespaceId] = $namespaceUri; - $root->setAttribute($namespaceId, $namespaceUri); - } - $nodeName = str_replace('xmlns:', '', $namespaceId) . ':' . str_replace($namespaceUri, '', $predicate); - break; - } + [$namespace, $property] = explode('#', $predicate, 2); + $namespace = "$namespace#"; + + if (!isset($namespaces[$namespace])) { + $namespaceId = sprintf('ns%u', ++$namespaceCounter); + $namespaces[$namespace] = $namespaceId; + $root->setAttribute("xmlns:$namespaceId", $namespace); } - $resourceValue = false; - foreach ($allNs as $namespaceUri) { - if ( - preg_match('/^' . preg_quote($namespaceUri, '/') . '/', $object) || - preg_match("/^http:\/\/(.*)#[a-zA-Z1-9]*/", $object) - ) { - $resourceValue = true; - break; + $namespaceId = $namespaces[$namespace]; + $nodeName = "$namespaceId:$property"; + + try { + $node = $dom->createElement($nodeName); + if (!empty($lang)) { + $node->setAttribute('xml:lang', $lang); } - } - if (!is_null($nodeName)) { - try { - $node = $dom->createElement($nodeName); - if (!empty($lang)) { - $node->setAttribute('xml:lang', $lang); - } - - if ($resourceValue) { - $node->setAttribute('rdf:resource', $object); - } else { - if (!empty($object) && !is_null($object)) { - - /** - * Replace the CDATA section inside XML fields by a replacement tag: - * to - * @todo check if this behavior is the right - */ - $object = str_replace([''], ['', ''], $object); - - $node->appendChild($dom->createCDATASection($object)); - } - } - $description->appendChild($node); - } catch (DOMException $de) { - //print $de; + + if (preg_match("/^http:\/\/(.*)#[a-zA-Z1-9]*/", $object)) { + $node->setAttribute('rdf:resource', $object); + } elseif (!empty($object) && !is_null($object)) { + + /** + * Replace the CDATA section inside XML fields by a replacement tag: + * to + * @todo check if this behavior is the right + */ + $object = str_replace([''], ['', ''], $object); + + $node->appendChild($dom->createCDATASection($object)); } + $description->appendChild($node); + } catch (DOMException $de) { + //print $de; } } $root->appendChild($description); From 4ea934e10f2b7dbec87144c1bcb536478ba30537 Mon Sep 17 00:00:00 2001 From: Sergei Mikhailov Date: Wed, 11 Aug 2021 11:54:42 +0200 Subject: [PATCH 2/5] chore: unwrap curly braces from simple variables in `class.ApiModelOO`'s string interpolations --- core/kernel/impl/class.ApiModelOO.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/kernel/impl/class.ApiModelOO.php b/core/kernel/impl/class.ApiModelOO.php index 754bc0587..a8523d1c9 100644 --- a/core/kernel/impl/class.ApiModelOO.php +++ b/core/kernel/impl/class.ApiModelOO.php @@ -98,7 +98,7 @@ public function getResourceDescriptionXML($uriResource) $namespaces = [ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' => 'rdf', 'http://www.w3.org/2000/01/rdf-schema#' => 'rdfs', - ROOT_URL . '#' => "ns{$namespaceCounter}", + ROOT_URL . '#' => "ns$namespaceCounter", ]; try { From 281c63625456bb77fa8300de575d691a58e278c8 Mon Sep 17 00:00:00 2001 From: Sergei Mikhailov Date: Wed, 11 Aug 2021 12:03:43 +0200 Subject: [PATCH 3/5] feat: log rdf properties export errors --- core/kernel/impl/class.ApiModelOO.php | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/core/kernel/impl/class.ApiModelOO.php b/core/kernel/impl/class.ApiModelOO.php index a8523d1c9..4ca4674eb 100644 --- a/core/kernel/impl/class.ApiModelOO.php +++ b/core/kernel/impl/class.ApiModelOO.php @@ -24,6 +24,7 @@ use oat\generis\model\OntologyRdfs; use Doctrine\DBAL\DBALException; use oat\generis\model\data\import\RdfImporter; +use oat\oatbox\log\LoggerAwareTrait; use oat\oatbox\service\ServiceManager; use Zend\ServiceManager\ServiceLocatorInterface; @@ -46,6 +47,8 @@ */ class core_kernel_impl_ApiModelOO extends core_kernel_impl_Api implements core_kernel_api_ApiModel { + use LoggerAwareTrait; + // --- ASSOCIATIONS --- @@ -90,6 +93,8 @@ public function importXmlRdf($targetNameSpace, $fileLocation) */ public function getResourceDescriptionXML($uriResource) { + $returnValue = ''; + $dbWrapper = core_kernel_classes_DbWrapper::singleton(); $subject = $dbWrapper->quote($uriResource); @@ -156,19 +161,17 @@ public function getResourceDescriptionXML($uriResource) $node->appendChild($dom->createCDATASection($object)); } $description->appendChild($node); - } catch (DOMException $de) { - //print $de; + } catch (DOMException $exception) { + $this->logCritical($exception->getMessage(), ['exception' => $exception]); } } $root->appendChild($description); $returnValue = $dom->saveXml(); - } catch (DomException $e) { - print $e; + } catch (DomException $exception) { + $this->logError($exception->getMessage(), ['exception' => $exception]); + print $exception; } - - - return (string) $returnValue; } From f21ddc50eec216c532134ce53602dfe906e7244f Mon Sep 17 00:00:00 2001 From: Sergei Mikhailov Date: Wed, 11 Aug 2021 12:39:00 +0200 Subject: [PATCH 4/5] chore: extract XML namespace generation into additional methods of `class.ApiModelOO` --- core/kernel/impl/class.ApiModelOO.php | 66 +++++++++++++++++++-------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/core/kernel/impl/class.ApiModelOO.php b/core/kernel/impl/class.ApiModelOO.php index 4ca4674eb..f7fdfa9b6 100644 --- a/core/kernel/impl/class.ApiModelOO.php +++ b/core/kernel/impl/class.ApiModelOO.php @@ -62,6 +62,12 @@ class core_kernel_impl_ApiModelOO extends core_kernel_impl_Api implements core_k */ private static $instance = null; + /** @var string[] */ + private $namespaces = []; + + /** @var int */ + private $customNamespacesCounter = 0; + // --- OPERATIONS --- @@ -98,22 +104,12 @@ public function getResourceDescriptionXML($uriResource) $dbWrapper = core_kernel_classes_DbWrapper::singleton(); $subject = $dbWrapper->quote($uriResource); - $namespaceCounter = core_kernel_persistence_smoothsql_SmoothModel::DEFAULT_WRITABLE_MODEL; - - $namespaces = [ - 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' => 'rdf', - 'http://www.w3.org/2000/01/rdf-schema#' => 'rdfs', - ROOT_URL . '#' => "ns$namespaceCounter", - ]; - try { $dom = new DOMDocument(); $dom->formatOutput = true; $root = $dom->createElement('rdf:RDF'); - foreach ($namespaces as $namespace => $namespaceId) { - $root->setAttribute("xmlns:$namespaceId", $namespace); - } + $this->addCoreNamespaces($root); $dom->appendChild($root); $description = $dom->createElement('rdf:Description'); @@ -130,15 +126,8 @@ public function getResourceDescriptionXML($uriResource) } [$namespace, $property] = explode('#', $predicate, 2); - $namespace = "$namespace#"; - if (!isset($namespaces[$namespace])) { - $namespaceId = sprintf('ns%u', ++$namespaceCounter); - $namespaces[$namespace] = $namespaceId; - $root->setAttribute("xmlns:$namespaceId", $namespace); - } - - $namespaceId = $namespaces[$namespace]; + $namespaceId = $this->addCustomNamespace($root, $namespace); $nodeName = "$namespaceId:$property"; try { @@ -149,7 +138,7 @@ public function getResourceDescriptionXML($uriResource) if (preg_match("/^http:\/\/(.*)#[a-zA-Z1-9]*/", $object)) { $node->setAttribute('rdf:resource', $object); - } elseif (!empty($object) && !is_null($object)) { + } elseif (!empty($object)) { /** * Replace the CDATA section inside XML fields by a replacement tag: @@ -423,4 +412,41 @@ private function createClassCollection(string $debug = ''): core_kernel_classes_ { return new core_kernel_classes_ContainerCollection(new core_kernel_classes_Container(), $debug); } + + private function addCoreNamespaces(DOMElement $root): void + { + $this->namespaces = [ + 'http://www.w3.org/1999/02/22-rdf-syntax-ns' => 'rdf', + 'http://www.w3.org/2000/01/rdf-schema' => 'rdfs', + ]; + + foreach ($this->namespaces as $namespace => $namespaceId) { + $this->addNamespace($root, $namespaceId, $namespace); + } + + $this->customNamespacesCounter = 0; + $this->addCustomNamespace($root, ROOT_URL); + } + + /** + * @param DOMElement $root + * @param string $namespace + * + * @return string|null A namespace ID + */ + private function addCustomNamespace(DOMElement $root, string $namespace): string + { + if (!isset($this->namespaces[$namespace])) { + $namespaceId = sprintf('ns%u', ++$this->customNamespacesCounter); + $this->namespaces[$namespace] = $namespaceId; + $this->addNamespace($root, $namespaceId, $namespace); + } + + return $this->namespaces[$namespace]; + } + + private function addNamespace(DOMElement $root, string $namespaceId, string $namespace): void + { + $root->setAttribute("xmlns:$namespaceId", "$namespace#"); + } } From 8b6512aa74ca685e4805364f5c07c94a01aa06a7 Mon Sep 17 00:00:00 2001 From: Sergei Mikhailov Date: Wed, 11 Aug 2021 12:55:22 +0200 Subject: [PATCH 5/5] fix: use `LOCAL_NAMESPACE` value as an initial custom namespace of a resulting RDF export --- core/kernel/impl/class.ApiModelOO.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/kernel/impl/class.ApiModelOO.php b/core/kernel/impl/class.ApiModelOO.php index f7fdfa9b6..e4652352d 100644 --- a/core/kernel/impl/class.ApiModelOO.php +++ b/core/kernel/impl/class.ApiModelOO.php @@ -425,7 +425,7 @@ private function addCoreNamespaces(DOMElement $root): void } $this->customNamespacesCounter = 0; - $this->addCustomNamespace($root, ROOT_URL); + $this->addCustomNamespace($root, LOCAL_NAMESPACE); } /**