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

    @asmm
    Исправления для корректной работы с пустыми тегами:
    <?php
    $in = new DOMDocument();
    $in->load($argv[1]);
    
    $out = new XMLWriter();
    $out->openMemory();
    
    $index = 0;
    $stack = [[$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->nodeValue === '' && $node->lastChild === null) {
          $stack[] = null;
        }
        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";
    
    ?>