2010-10-20 6 views
2

я иметь следующую структуру XML:Выберите некоторые, но не все дочерние узлы

<?xml version="1.0" encoding="ISO-8859-1"?> 
<articles> 
    <article id="1"> 
    <title>Article title 001</title> 
    <short>Short text</short> 
    <long>Long text</long> 
    </article> 
    <article id="2"> 
    <title>Article title 002</title> 
    <short>Short text</short> 
    <long>Long text</long> 
    </article> 
</articles> 

Я хочу, чтобы выбрать только <title> и <short>.

В настоящее время используется для отображения все:

$queryResult = $xpathvar->query('//articles/article'); // works fine grabs all articles 
foreach($queryResult as $result){ 
    echo $result->textContent; 
} 

Ожидаемый результат будет:

Название статьи 001

Короткий текст

Любая помощь будет принята с благодарностью.

Рабочее решение!

if ($artId == "") { 
    $queryResult = $xpathvar->query('//articles/article/*'); // grab all children 
    foreach($queryResult as $result){ 
     if($result->nodeName === 'title' || $result->nodeName === 'short') { 
      echo $result->textContent; 
     } 
    } 
}else{ 
    $queryResult = $xpathvar->query(sprintf('//articles/article[@id="%s"]/*', $artId)); // Show requested article 
    foreach($queryResult as $result){ 
     if($result->nodeName === 'title' || $result->nodeName === 'long') { 
      echo $result->textContent; 
     } 
    } 
} 
+0

Какой результат вы хотели бы увидеть? –

+0

Хороший вопрос, +1. См. Мой ответ для гораздо более эффективного решения - также более «XPath-y». :) –

ответ

3

Вы можете использовать

/articles/article/*[name()="title" or name()="short"] 

, который будет возвращать только ребенок любых «статьи/статей» с именем элемента из «заголовка» или «короткого».


В качестве альтернативы, изменить XPath к /articles/article/* для извлечения всех ChildNodes статьи и при переборе $results чек, если DOMNode::nodeName это «название» или «короткий», например,

$queryResult = $xpathvar->query('/articles/article/*'); // grab all children 
foreach($queryResult as $result){ 
    if($result->nodeName === 'title' || $result->nodeName === 'short') { 
     echo $result->textContent; 
    } 
} 

Если вы не хотите, чтобы изменить XPath, вы должны итерируем childNodes статьи, например,

$queryResult = $xpathvar->query('/articles/article'); 
foreach($queryResult as $result) { 
    foreach($result->childNodes as $child) {  
    if($child->nodeName === 'title' || $child->nodeName === 'short') { 
     echo $child->textContent; 
    } 
} 
+0

Спасибо, Гордон, ваше первое решение работает, но ... Мне также нужно выбрать только одну статью на основе ID и отобразить заголовок и длинный текст. – StefWill

+0

@StefWill XPath будет '// articles/article [@ id = 1]/* [name() =" title "или name() =" long "]'. Взгляните на это [Xpath Tutorial] (http://www.w3schools.com/XPath/default.asp) – Gordon

+1

+1 Хороший ответ.Но, пожалуйста, не начинайте выражение с помощью оператора '//', когда схема хорошо известна. – 2010-10-20 13:31:01

1

Использование:

/*/*/*[self::title or self::short] 

или если title и short дети определенного article с известной @id (скажем, '2') должны быть отображены:

/*/article[@id='2']/*[self::title or self::short] 

Всегда старайтесь избегать использования // аббревиатура, когда это возможно (когда известна структура документа XML).

Использование // очень часто приводит к грубо-неэффективной оценке, потому что // вызывает полное (вспомогательное) дерево, внедренное в текущий узел для поиска.

+0

+1 для 'self :: title' вместо' name() = 'title'' – LarsH

Смежные вопросы