Ответы пользователя по тегу XSD
  • Реализация алгоритма нормализации XML для СМЭВ 3?

    IvanU7n
    @IvanU7n
    Для будущих искателей: вот такой монстрик у меня получился (PHP 7.1). Он проходит все проверки из МР 3.5, но, возможно, некоторых нюансов не учитывает.
    <?php
    $in = new DOMDocument();
    $in->load($argv[1]);
    
    $out = new XMLWriter();
    $out->openMemory();
    
    $index = 0;
    $stack = [null, [$in->documentElement, []]];
    while (count($stack)) {
    	$item = array_pop($stack);
    	if ($item === null) {
    		$out->text('');
    		$out->endElement();
    		continue;
    	}
    	[$node, $nsList] = $item;
    	if ($node->nodeType == XML_ELEMENT_NODE) {
    		// Let the magic begin! ;)
    		// The element itself.
    		if ($node->namespaceURI !== null) {
    			$thisLevel = false;
    			if (($nsList[$node->namespaceURI] ?? null) === null) {
    				$thisLevel = true;
    				$nsList[$node->namespaceURI] = 'ns' . ++$index;
    			}
    			$out->startElement("{$nsList[$node->namespaceURI]}:{$node->localName}");
    			if ($thisLevel) {
    				$out->writeAttribute("xmlns:{$nsList[$node->namespaceURI]}", $node->namespaceURI);
    			}
    		}
    		else {
    			$out->startElement($node->localName);
    		}
    		// Attributes.
    		$attrs = iterator_to_array($node->attributes);
    		usort($attrs, function($a, $b) {
    			if ($a->namespaceURI !== null && $b->namespaceURI === null) return -1;
    			else if ($a->namespaceURI === null && $b->namespaceURI !== null) return 1;
    			else return strcmp($a->namespaceURI, $b->namespaceURI) ?: strcmp($a->localName, $b->localName);
    		});
    		foreach ($attrs as $attr) {
    			if ($attr->namespaceURI !== null && ($nsList[$attr->namespaceURI] ?? null) === null) {
    				$nsList[$attr->namespaceURI] = 'ns' . ++$index;
    				$out->writeAttribute("xmlns:{$nsList[$attr->namespaceURI]}", $attr->namespaceURI);
    			}
    		}
    		foreach ($attrs as $attr) {
    			if ($attr->namespaceURI !== null) {
    				$out->writeAttribute("{$nsList[$attr->namespaceURI]}:{$attr->localName}", $attr->nodeValue);
    			}
    			else {
    				$out->writeAttribute($attr->localName, $attr->nodeValue);
    			}
    		}
    	}
    	else if ($node->nodeType == XML_TEXT_NODE && strlen(trim($node->nodeValue))) {
    		$out->text($node->nodeValue);
    	}
    
    	if ($node->lastChild !== null) {
    		$stack[] = null;
    		for ($node = $node->lastChild; $node !== null; $node = $node->previousSibling) {
    			$stack[] = [$node, $nsList];
    		}
    	}
    }
    
    echo $out->outputMemory(), "\n";
    
    ?>
    Ответ написан
    9 комментариев