Добавление отступа с DOMDocument в PHP

Я использовал $priceResult как массив, содержащий объекты категорий. Я думаю, это выглядело бы примерно так:

$priceResult = array()

foreach($pricing->categories as $category){ 
    $c = new stdClass();
    $c->CategoryCode = $category->categoryCode;
    $c->CategoryDescription = $category->category_description;
    $c->Products = array();

    foreach($category->products as $product){
        $p = new stdClass();
        $p->ProductCode = null; // $product->something? no idea where this is
        $p->CountNumber = $product->productInfo->product->product_type->quantDetails;
        $p->ProductDescription = $product->productInfo->product->product_type->desc;
        $p->PriceAmount = $product->pricing->MainPrice;
        $c->Products[] = $p;
    }
    $priceResult[] = $c;
}

Я должен сказать, что исходные данные, похоже, имеют очень странную структуру.

23
задан Benjamin 1 April 2016 в 22:32
поделиться

5 ответов

After some help from John and playing around with this on my own, it seems that even DOMDocument's inherent support for formatting didn't meet my needs. So, I decided to write my own indentation function.

This is a pretty crude function that I just threw together quickly, so if anyone has any optimization tips or anything to say about it in general, I'd be glad to hear it!

function indent($text)
{
    // Create new lines where necessary
    $find = array('>', '</', "\n\n");
    $replace = array(">\n", "\n</", "\n");
    $text = str_replace($find, $replace, $text);
    $text = trim($text); // for the \n that was added after the final tag

    $text_array = explode("\n", $text);
    $open_tags = 0;
    foreach ($text_array AS $key => $line)
    {
        if (($key == 0) || ($key == 1)) // The first line shouldn't affect the indentation
            $tabs = '';
        else
        {
            for ($i = 1; $i <= $open_tags; $i++)
                $tabs .= "\t";
        }

        if ($key != 0)
        {
            if ((strpos($line, '</') === false) && (strpos($line, '>') !== false))
                $open_tags++;
            else if ($open_tags > 0)
                $open_tags--;
        }

        $new_array[] = $tabs . $line;

        unset($tabs);
    }
    $indented_text = implode("\n", $new_array);

    return $indented_text;
}
7
ответ дан 29 November 2019 в 02:16
поделиться

Я попытался запустить приведенный ниже код, установив formatOutput и preserveWhiteSpace в другими способами, и единственный член, который имеет какое-либо влияние на вывод, является formatOutput . Можете ли вы запустить приведенный ниже сценарий и посмотреть, работает ли он?

<?php
    echo "<pre>";
    $foo = new DOMDocument();
    //$foo->preserveWhiteSpace = false;
    $foo->formatOutput = true;
    $root = $foo->createElement("root");
    $root->setAttribute("attr", "that");
    $bar = $foo->createElement("bar", "some text in bar");
    $baz = $foo->createElement("baz", "some text in baz");
    $foo->appendChild($root);
    $root->appendChild($bar);
    $root->appendChild($baz);
    echo htmlspecialchars($foo->saveXML());
    echo "</pre>";
?>
3
ответ дан 29 November 2019 в 02:16
поделиться

Большинство ответов в этой теме посвящено текстовому потоку xml. Вот еще один подход, использующий функции dom для выполнения работы с отступами. Метод loadXML () dom импортирует символы отступов, присутствующие в источнике xml, как текстовые узлы. Идея состоит в том, чтобы удалить такие текстовые узлы из DOM, а затем воссоздать правильно отформатированные (см. Комментарии в коде ниже для более подробной информации).

Функция xmlIndent () реализована как метод класса indentDomDocument, который унаследован от domDocument. Ниже приведен полный пример того, как его использовать:

$dom = new indentDomDocument("1.0");
$xml = file_get_contents("books.xml");

$dom->loadXML($xml);
$dom->xmlIndent();
echo $dom->saveXML();

class indentDomDocument extends domDocument {
    public function xmlIndent() {
        // Retrieve all text nodes using XPath
        $x = new DOMXPath($this);
        $nodeList = $x->query("//text()");
        foreach($nodeList as $node) {
            // 1. "Trim" each text node by removing its leading and trailing spaces and newlines.
            $node->nodeValue = preg_replace("/^[\s\r\n]+/", "", $node->nodeValue);
            $node->nodeValue = preg_replace("/[\s\r\n]+$/", "", $node->nodeValue);
            // 2. Resulting text node may have become "empty" (zero length nodeValue) after trim. If so, remove it from the dom.
            if(strlen($node->nodeValue) == 0) $node->parentNode->removeChild($node);
        }
        // 3. Starting from root (documentElement), recursively indent each node. 
        $this->xmlIndentRecursive($this->documentElement, 0);
    } // end function xmlIndent

    private function xmlIndentRecursive($currentNode, $depth) {
        $indentCurrent = true;
        if(($currentNode->nodeType == XML_TEXT_NODE) && ($currentNode->parentNode->childNodes->length == 1)) {
            // A text node being the unique child of its parent will not be indented.
            // In this special case, we must tell the parent node not to indent its closing tag.
            $indentCurrent = false;
        }
        if($indentCurrent && $depth > 0) {
            // Indenting a node consists of inserting before it a new text node
            // containing a newline followed by a number of tabs corresponding
            // to the node depth.
            $textNode = $this->createTextNode("\n" . str_repeat("\t", $depth));
            $currentNode->parentNode->insertBefore($textNode, $currentNode);
        }
        if($currentNode->childNodes) {
            $indentClosingTag = false;
            foreach($currentNode->childNodes as $childNode) $indentClosingTag = $this->xmlIndentRecursive($childNode, $depth+1);
            if($indentClosingTag) {
                // If children have been indented, then the closing tag
                // of the current node must also be indented.
                $textNode = $this->createTextNode("\n" . str_repeat("\t", $depth));
                $currentNode->appendChild($textNode);
            }
        }
        return $indentCurrent;
    } // end function xmlIndentRecursive

} // end class indentDomDocument
1
ответ дан 29 November 2019 в 02:16
поделиться

Йо выглядывает,

только что обнаружил, что, очевидно, корневой элемент XML не может содержать текстовые дочерние элементы. Это не интуитивно понятно. е. Но, по-видимому, это причина того, что, например,

$x = new \DOMDocument;
$x -> preserveWhiteSpace = false;
$x -> formatOutput = true;
$x -> loadXML('<root>a<b>c</b></root>');
echo $x -> saveXML();

не сможет отступить.

https://bugs.php.net/bug.php?id=54972

Итак, поехали, h. т. час и т. д.

-1
ответ дан 29 November 2019 в 02:16
поделиться
header("Content-Type: text/xml");

$str = "";
$str .= "<customer>";
$str .= "<offer>";
$str .= "<opened></opened>";
$str .= "<redeemed></redeemed>";
$str .= "</offer>";
echo $str .= "</customer>";

Если вы используете какое-либо расширение, кроме .xml, то сначала установите правильное значение заголовка header Content-Type.

-2
ответ дан 29 November 2019 в 02:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: