Строка XPath для всех дочерних элементов пространств имен - PullRequest
0 голосов
/ 29 декабря 2010

Просто начать работу с XPath и использовать его реализацию с объектами PHP SimpleXML. Прямо сейчас я использую //zuq:* для создания массива SimpleXML объектов с префиксом zuq в данном документе. Однако я бы хотел, чтобы объекты SimpleXML ссылались на всех потомков независимо от пространства имен. Я пытался использовать //child::zuq:*, но создаваемые им деревья SimpleXML, похоже, не полны.

По сути, захваченные объекты должны быть всеми объектами верхнего уровня пространства имен zuq по всему документу, содержащими все элементы-потомки независимо от пространства имен, включая zuq.

tl; dr: Как мне создать дерево объектов SimpleXML из данного документа, где каждый корневой объект SimpleXML является элементом документа самого высокого уровня данного пространства имен (например, zuq), содержащим все потомки указанного элемента независимо от пространства имен потомка? XPath не является обязательным, но, похоже, является лучшим выбором, основываясь на моем чтении.


test.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:zuq="http://localhost/zuq">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>

<body>
    <h1>Heading</h1>
    <p>Paragraph</p>
    <zuq:region name="myRegion">
        <div class="myClass">
            <h1><zuq:data name="myDataHeading" /></h1>
            <p>
                <zuq:data name="myDataParagraph">
                    <zuq:format type="trim">
                        <zuq:param name="length" value="200" />
                        <zuq:param name="append">
                            <span class="paragraphTrimOverflow">...</span>
                        </zuq:param>
                    </zuq:format>
                </zuq:data>
            </p>
        </div>
    </zuq:region>
</body>
</html>

$sxml = simplexml_load_file('test.html');
$sxml_zuq = $sxml->xpath('//zuq:*/descendant-or-self::node()');
print_r($sxml_zuq);

Производит:

Array
(
[0] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [name] => myRegion
            )

        [div] => SimpleXMLElement Object
            (
                [@attributes] => Array
                    (
                        [class] => myClass
                    )

                [h1] => SimpleXMLElement Object //I don't know why these don't contain their zuq descendants
                    (
                    )

                [p] => SimpleXMLElement Object
                    (
                    )

            )

    )

[1] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [name] => myRegion
            )

        [div] => SimpleXMLElement Object
            (
                [@attributes] => Array
                    (
                        [class] => myClass
                    )

                [h1] => SimpleXMLElement Object
                    (
                    )

                [p] => SimpleXMLElement Object
                    (
                    )

            )

    )

[2] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [class] => myClass
            )

        [h1] => SimpleXMLElement Object
            (
            )

        [p] => SimpleXMLElement Object
            (
            )

    )

[3] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [class] => myClass
            )

        [h1] => SimpleXMLElement Object
            (
            )

        [p] => SimpleXMLElement Object
            (
            )

    )

[4] => SimpleXMLElement Object
    (
    )

[5] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [name] => myDataHeading
            )

    )

[6] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [class] => myClass
            )

        [h1] => SimpleXMLElement Object
            (
            )

        [p] => SimpleXMLElement Object
            (
            )

    )

[7] => SimpleXMLElement Object
    (
    )

[8] => SimpleXMLElement Object
    (
    )

[9] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [name] => myDataParagraph
            )

    )

[10] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [name] => myDataParagraph
            )

    )

[11] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [type] => trim
            )

    )

[12] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [type] => trim
            )

    )

[13] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [name] => length
                [value] => 200
            )

    )

[14] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [type] => trim
            )

    )

[15] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [name] => append
            )

        [span] => ...
    )

[16] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [name] => append
            )

        [span] => ...
    )

[17] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [class] => paragraphTrimOverflow
            )

        [0] => ...
    )

[18] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [class] => paragraphTrimOverflow
            )

        [0] => ...
    )

[19] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [name] => append
            )

        [span] => ...
    )

[20] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [type] => trim
            )

    )

[21] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [name] => myDataParagraph
            )

    )

[22] => SimpleXMLElement Object
    (
    )

[23] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [class] => myClass
            )

        [h1] => SimpleXMLElement Object
            (
            )

        [p] => SimpleXMLElement Object
            (
            )

    )

[24] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [name] => myRegion
            )

        [div] => SimpleXMLElement Object
            (
                [@attributes] => Array
                    (
                        [class] => myClass
                    )

                [h1] => SimpleXMLElement Object
                    (
                    )

                [p] => SimpleXMLElement Object
                    (
                    )

            )

    )

)

Ответы [ 2 ]

2 голосов
/ 29 декабря 2010

Не доверяйте выводу оператора print_r ... кажется, что он показывает пустой объект, но в моем тестировании дети на самом деле все еще там.Например, начиная с кода выше:

$sxml = simplexml_load_file('test.html');
$sxml_zuq = $sxml->xpath('//zuq:*/descendant-or-self::node()');

Если я впоследствии попробую команду, подобную этой:

print_r($sxml_zuq[0]->div->h1);

, я получу такой вывод:

SimpleXMLElement Object
(
)

Вроде бы пусто, верно?Но если я изменю команду так, чтобы она выглядела так:

echo $sxml_zuq[0]->div->h1->asXML();

Я получу результирующее дерево с дочерним пространством имен:

<h1><zuq:data name="myDataHeading"/></h1>

Я не уверен на 100%, почему это так;Вероятно, это как-то связано с оператором print_r, который пытается сгладить объект simplexml и неправильно обрабатывает пространства имен.Но когда вы сохраняете сами объекты simplexml, которые возвращаются из вашего вызова xpath, все дочерние объекты сохраняются.

Теперь, что касается самого вашего xpath, вы, вероятно, НЕ ХОТИТЕ ось «потомок или сам», потому что она будет соответствовать не только элементу верхнего уровня zuq, но и всем его дочерним элементам.и создайте массив большего размера, чем вы на самом деле пытаетесь вернуть (если я не понимаю, о чем вы спрашиваете).Если вы попробуете что-то вроде этого:

$sxml_zuq = $sxml->xpath('//zuq:*[not(ancestor::zuq:*)]');

, вы получите массив ТОЛЬКО верхнего уровня элементов пространства имен zuq.(хотя ваш пример XML имел только один такой элемент верхнего уровня, ваши фактические данные могут иметь несколько братьев и сестер на этом уровне).Затем вы можете захватить содержимое каждого из этих элементов верхнего уровня следующим образом:

foreach ($sxml_zuq as $zuq_node) {
     echo ($zuq_node->asXML());
}

Все становится немного сложнее, если вы хотите повторить этот процесс, но выполните поиск элементов верхнего уровня (или любых других)в пространстве имен по умолчанию;вам нужно будет использовать функцию registerNamespace, чтобы присвоить пространству имен по умолчанию временный префикс, и выполнить поиск xpath по нему.

1 голос
/ 29 декабря 2010

Я думаю, что вы ищете //zuq:*/descendant-or-self::*.Это приведет к тому, что все поддеревья с корнем будут иметь префикс zuq namespace.

Кажется, что наблюдаемое поведение является артефактом SimpleXML (спецификация XPath не имеет дело с деревьями в выводе запроса XPath, только с отдельными узлами).).Вероятно, вы можете решить это, используя что-то вроде

//zuq:*[not(ancestor::zuq:*)]/descendant-or-self::*

ancestor [...] проверяет, существует ли предок, для которого выполняется условие - т.е. есть ли предок с zuqпрефикс.Таким образом, вы должны получить только zuq: корни, которые не имеют zuq: ancestor.

...