0

I need to loop through the Ancestors nodes in order to get corresponding BrowseNodeId and Name values. How do I do this using XPath? I'm trying something like the the following, but it's not working:

//BrowseNode[1]//Ancestors[1]/BrowseNode/BrowseNodeId/text()
//BrowseNode[1]//Ancestors[1]/BrowseNode/Name/text()

I think the //Ancestors part of the XPath is actually searching the entire XML tree. What I need to do is visit each node to get the needed values. How do I do this? In the example below, I want: Europe -> History -> Subjects -> Books.

Example XML:

    <BrowseNode>
        <BrowseNodeId>4952</BrowseNodeId>
        <Name>France</Name>
        <Ancestors>
            <BrowseNode>
                <BrowseNodeId>4935</BrowseNodeId>
                <Name>Europe</Name>
                <Ancestors>
                    <BrowseNode>
                        <BrowseNodeId>9</BrowseNodeId>
                        <Name>History</Name>
                        <Ancestors>
                            <BrowseNode>
                                <BrowseNodeId>1000</BrowseNodeId>
                                <Name>Subjects</Name>
                                <IsCategoryRoot>1</IsCategoryRoot>
                                <Ancestors>
                                    <BrowseNode>
                                        <BrowseNodeId>283155</BrowseNodeId>
                                        <Name>Books</Name>
                                    </BrowseNode>
                                </Ancestors>
                            </BrowseNode>
                        </Ancestors>
                    </BrowseNode>
                </Ancestors>
            </BrowseNode>
        </Ancestors>
    </BrowseNode>
1
  • @Alejandro 's answer is better than the one you have accepted. The accepted answer is in fact wrong, because doesnt obtain any node at all: the XPath expression /Ancestors/BrowseNode doesn't select any node because your XML document doesn't have a top element named Ancestors. Please, consider accepting a correct answer, because accepting a wrong answer may mislead other people. Commented Jan 8, 2011 at 17:10

5 Answers 5

1

In the example below, I want: Europe -> History -> Subjects -> Books.

I think you need:

//Ancestors/BrowseNode/Name

Or just iterate over //Ancestors/BrowseNode results and get the Name and BrowseNodeId children with any DOM method.

Sign up to request clarification or add additional context in comments.

Comments

0
$browse_nodes = $xml->BrowseNode;
foreach ($browse_nodes as $browse_node) {
    echo $browse_node->BrowseNodeId.nodeValue;
    echo $browse_node->Name.nodeValue;
}

3 Comments

I don't think this works. The XML I have is huge, and has a lot of the top level BrowseNode elements. Also, I am only interested in the Ancestors/BrowseNode of each top level BrowseNode element. Meaning, I need something like this: //BrowseNode[1]/Ancestors/BrowseNode, then //BrowseNode[2]/Ancestors/BrowseNode, then //BrowseNode[3]/Ancestors/BrowseNode ... The problem is that the // is searching the entire tree, I think. What I need is to walk the sub-tree of each top level BrowseNode
oic, maybe try single slash xpath('/Ancestors/BrowseNode'), then xpath('/Ancestors/BrowseNode/Ancestors/BrowseNode'), etc.
probably don't need xpath for this. you cn iterate through a set of children like you would an array.
0

Maybe try to locate the final node, then extract is ancestors ?

<?php

$xml = "
    <BrowseNode>
        <BrowseNodeId>4952</BrowseNodeId>
        <Name>France</Name>
        <Ancestors>
            <BrowseNode>
                <BrowseNodeId>4935</BrowseNodeId>
                <Name>Europe</Name>
                <Ancestors>
                    <BrowseNode>
                        <BrowseNodeId>9</BrowseNodeId>
                        <Name>History</Name>
                        <Ancestors>
                            <BrowseNode>
                                <BrowseNodeId>1000</BrowseNodeId>
                                <Name>Subjects</Name>
                                <IsCategoryRoot>1</IsCategoryRoot>
                                <Ancestors>
                                    <BrowseNode>
                                        <BrowseNodeId>283155</BrowseNodeId>
                                        <Name>Books</Name>
                                    </BrowseNode>
                                </Ancestors>
                            </BrowseNode>
                        </Ancestors>
                    </BrowseNode>
                </Ancestors>
            </BrowseNode>
        </Ancestors>
    </BrowseNode>
";


$sxe = simplexml_load_string($xml);

// Set the target to reach
$target = current($sxe->xpath("//BrowseNode[./BrowseNodeId = '283155']"));

// Get all names from root to target
$names = array_map('strval', $target->xpath('ancestor-or-self::Ancestors/BrowseNode/Name'));
print_r($names);
// Array
// (
//     [0] => Europe
//     [1] => History
//     [2] => Subjects
//     [3] => Books
// )

// Get all ids from root to target
$ids = array_map('strval', $target->xpath('ancestor-or-self::Ancestors/BrowseNode/BrowseNodeId'));
print_r($ids);
// Array
// (
//     [0] => 4935
//     [1] => 9
//     [2] => 1000
//     [3] => 283155
// )

// Final
$combined = array_combine($ids, $names);
print_r($combined);
// Array
// (
//     [4935] => Europe
//     [9] => History
//     [1000] => Subjects
//     [283155] => Books
// )

Comments

0
/BrowseNode/Ancestors//BrowseNode/Name/text()

Will work with you sample.

However, it will search all nodes descandant to the "first" Ancestors element. Reversing and looking from the deepest BrowseNode would do pretty much the same.

In XSLT the viable and necessary alternative would be using keys for better efficiency.

Comments

0

I may have misunderstood your description of precisely what you want, but hopefully not. This snippet looks for all of the "top level" BrowseNode elements and loops over them, getting their associated ancestor BrowseNode elements each time.

// Get top level BrowseNode elements
$browse_nodes = $xml->xpath('//BrowseNodes/BrowseNode');
foreach ($browse_nodes as $browse_node) {
    // Get ancestor BrowseNode elements
    $ancestors = $browse_node->xpath('Ancestors//BrowseNode');
    // Do whatever you like with them! :-)
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.