0

I have XML documents containing information of articles, that have a kind of hierarchy:

<?xml version="1.0" encoding="UTF-8"?>

<page>
<elements>

<element>
<type>article</type>
<id>1</id>
<parentContainerID>page</parentContainerID>
<parentContainerType>page</parentContainerType>
</element>

<element>
<type>article</type>
<id>2</id>
<parentContainerID>1</parentContainerID>
<parentContainerType>article</parentContainerType>
</element>

<element>
<type>photo</type>
<id>3</id>
<parentContainerID>2</parentContainerID>
<parentContainerType>article</parentContainerType>
</element>

<... more elements ..>

</elements>
</page>

The element has the node parentContainerID and the node parentContainerType. If parentContainerType == page, this is the master element. The parentContainerID shows what's the element's master. So it should look like: 1 <- 2 <- 3

Now I need to build a new page (html) of this stuff that looks like this: content of ID 1, content of ID 2, content of ID 3 (the IDs are not ongoing).

I guess this could be done with a recursive function. But I have no idea how to manage this?

2
  • 1
    “Now I need to build a new page (html) of this stuff that looks like this: content of ID 1, content of ID 2, content of ID 3” – just sequential - or nested, according to the parent/child relationship defined by the XML? If not nested, why would you use recursion here - the elements in the XML are not nested either, they are all on the same level. I’d probably just read that stuff into an array first, then sort that accordingly ... and then loop over it to generate the wanted output. Commented May 16, 2017 at 8:39
  • CBroe, according to the parent/child relationsship. Commented May 16, 2017 at 9:09

1 Answer 1

1

Here is no nesting/recursion in the XML. The <element/> nodes are siblings. To build the parent child relations I would suggest looping over the XML and building two arrays. One for the relations and one referencing the elements.

$xml = file_get_contents('php://stdin');

$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);

$relations = [];
$elements = [];
foreach ($xpath->evaluate('//element') as $element) {
  $id = (int)$xpath->evaluate('string(id)', $element);
  $parentId = (int)$xpath->evaluate('string(parentContainerID)', $element);
  $relations[$parentId][] = $id;
  $elements[$id] = $element;
}

var_dump($relations);

Output:

array(3) {
  [0]=>
  array(1) {
    [0]=>
    int(1)
  }
  [1]=>
  array(1) {
    [0]=>
    int(2)
  }
  [2]=>
  array(1) {
    [0]=>
    int(3)
  }
}

The relations array now contains the child ids for any parent, elements without a parent are in index 0. This allows you use a recursive function access the elements as a tree.

function traverse(
  int $parentId, callable $callback, array $elements, array $relations, $level = -1
) {
  if ($elements[$parentId]) {
     $callback($elements[$parentId], $parentId, $level);
  }
  if (isset($relations[$parentId]) && is_array($relations[$parentId])) {
    foreach ($relations[$parentId] as $childId) {
      traverse($childId, $callback, $elements, $relations, ++$level);
    }
  }
}

This executes the callback for each node. The proper implementation for this would be a RecursiveIterator but the function should do for the example.

traverse(
  0,
  function(DOMNode $element, int $id, int $level) use ($xpath) {
    echo str_repeat(' ', $level);
    echo $id, ": ", $xpath->evaluate('string(type)', $element), "\n";
  },
  $elements,
  $relations
);

Output:

1: article
 2: article
  3: photo

Notice that the $xpath object is provided as context to the callback. Because the $elements array contains the original nodes, you can use Xpath expression to fetch detailed data from the DOM related to the current element node.

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

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.