19 declare(strict_types=1);
    31     protected const PATH_TO_SCHEMA = __DIR__ . 
'/../../../../VocabValidation/controlled_vocabulary.xsd';
    39         ControlledVocabsRepository $vocab_repo,
    40         SlotHandler $slot_handler
    47     public function import(
string $xml_string): 
Result    49         $errors_or_xml = $this->
loadXML($xml_string);
    50         if (is_array($errors_or_xml)) {
    51             return new Result(...$errors_or_xml);
    53         $xml_path = new \DOMXPath($errors_or_xml);
    59             $errors[] = $e->getMessage();
    61         if (isset($slot) && $slot === SlotIdentifier::NULL) {
    62             $errors[] = 
'Cannot add vocabulary, invalid element or condition.';
    66         if (!empty($duplicates)) {
    67             $errors[] = 
'The following values are not unique: ' . implode(
', ', $duplicates);
    69         if (empty($errors) && isset($slot)) {
    71             if (!empty($already_exist)) {
    72                 $errors[] = 
'The following values already exist in other vocabularies of the element: ' .
    73                     implode(
', ', $already_exist);
    77         if (empty($errors) && isset($slot)) {
    84                 $errors[] = $e->getMessage();
    87         if (empty($errors) && isset($vocab_id)) {
    91         return new Result(...$errors);
   100         $use_internal_errors = libxml_use_internal_errors(
true);
   102         $xml = new \DOMDocument(
'1.0', 
'utf-8');
   103         $xml->loadXML($xml_string);
   105         if (!$xml->schemaValidate(self::PATH_TO_SCHEMA)) {
   107             foreach (libxml_get_errors() as 
$error) {
   108                 $errors[] = 
$error->message;
   112         libxml_clear_errors();
   113         libxml_use_internal_errors($use_internal_errors);
   115         return empty($errors) ? $xml : $errors;
   120         $node = $xml_path->query(
'//vocabulary/appliesTo/pathToElement')->item(0);
   126         $node = $xml_path->query(
'//vocabulary/appliesTo/condition/pathToElement')->item(0);
   127         return is_null($node) ? null : $this->
writeToPath($node, 
true);
   132         $node = $xml_path->query(
'//vocabulary/appliesTo/condition/@value')->item(0);
   133         return $node?->nodeValue;
   142         return $this->slot_handler->identiferFromPathAndCondition(
   151         $node = $xml_path->query(
'//vocabulary/source')->item(0);
   152         return (
string) $node?->nodeValue;
   160         $nodes = $xml_path->query(
'//vocabulary/values/value');
   161         foreach ($nodes as $node) {
   162             $label = $node->hasAttribute(
'label') ? $node->getAttribute(
'label') : 
'';
   163             $value = $node->nodeValue;
   164             yield $value => $label;
   176             if (in_array($value, $values) && !in_array($value, $duplicates)) {
   177                 $duplicates[] = $value;
   196         return iterator_to_array($this->vocab_repo->findAlreadyExistingValues(
   209         return $this->vocab_repo->create($slot, $source);
   217             $this->vocab_repo->addValueToVocabulary(
   227         $builder = $this->path_factory->custom();
   228         foreach ($path_in_xml->childNodes as $step) {
   229             if (!($step instanceof \DOMElement)) {
   232             if ($step->nodeName === 
'step') {
   233                 $builder = $builder->withNextStep($step->nodeValue);
   234             } elseif ($step->nodeName === 
'stepToSuper') {
   235                 $builder = $builder->withNextStepToSuperElement();
   238         return $builder->withRelative($relative)->get();