T3000
T3000

Reputation: 11

How to count the number of occurences of a child element of a given node in php?

I have the following XML file, and I would like to know the exact number of occurences the tag "ing" is present in each "ing-div" node. It will help me to determine the number of ingredients present for each ingredient title (i.e. FRUIT has 4 ingredients, Sponge Cake has 4 ingredients,...). Any suggestions?

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

<recipeml version="0.5">
  <recipe>
    <head>
      <title>1,000 Calorie-A-Bite Trifle</title>
      <categories>
        <cat>Desserts</cat>
        <cat>Usenet</cat></categories>
      <yield>1</yield></head>
    <ingredients>
      <ing-div>
        <title>FRUIT</title>
        <ing>
          <amt>
            <qty>3</qty>
            <unit/></amt>
          <item>Pears</item></ing>
        <ing>
          <amt>
            <qty>8</qty>
            <unit>ounces</unit></amt>
          <item>Raspberries (tinned or fresh)</item></ing>
        <ing>
          <amt>
            <qty>1</qty>
            <unit/></amt>
          <item>Passion fruit</item></ing>
        <ing>
          <amt>
            <qty/>
            <unit/></amt>
          <item>Dry sherry (1 bottle)</item></ing></ing-div>
      <ing-div>
        <title>SPONGE CAKE</title>
        <ing>
          <amt>
            <qty>1/2</qty>
            <unit>cups</unit></amt>
          <item>Butter</item></ing>
        <ing>
          <amt>
            <qty>10</qty>
            <unit>tablespoons</unit></amt>
          <item>Sugar, castor</item></ing>
        <ing>
          <amt>
            <qty>1 1/4</qty>
            <unit>cups</unit></amt>
          <item>Flour, self-raising</item></ing>
        <ing>
          <amt>
            <qty>2</qty>
            <unit/></amt>
          <item>Eggs (slightly whisked)</item></ing></ing-div>
      <ing-div>
        <title>CUSTARD</title>
        <ing>
          <amt>
            <qty>2</qty>
            <unit/></amt>
          <item>Eggs</item></ing>
        <ing>
          <amt>
            <qty>1</qty>
            <unit>pinch</unit></amt>
          <item>Salt</item></ing>
        <ing>
          <amt>
            <qty>1</qty>
            <unit>pinch</unit></amt>
          <item>Nutmeg</item></ing>
        <ing>
          <amt>
            <qty>10</qty>
            <unit>ounces</unit></amt>
          <item>Double cream (or use whipping cream)</item></ing></ing-div>
      <ing-div>
        <title>TOPPING</title>
        <ing>
          <amt>
            <qty>10</qty>
            <unit>ounces</unit></amt>
          <item>Double cream</item></ing>
        <ing>
          <amt>
            <qty/>
            <unit/></amt>
          <item>Roast almonds</item></ing></ing-div></ingredients>
    <directions>
      <step>  Peel and slice pears, drain raspberries if tinned, and scoop out passion
  fruit.  Place fruit in large trifle bowl and add an ample quantity of
  sherry. Leave for twenty-four hours to soak in the refrigerator.

  Preheat oven to 350 degrees F.  Cream butter and sugar until light and
  fluffy. Add eggs and about 2 T of flour and beat. Fold in rest of flour.
  Bake in 7-inch square tin for 25-30 mins until brown. Let cool. Slice into
  fingers and arrange on top of fruit. More sherry may be added at this
  point.

  Pour one large glass of sherry.  Mix eggs and add all ingredients to small
  bowl.  Place bowl in pan of simmering water. Stir continuously with wooden
  spoon, sipping sherry, until custard thickens. This takes about ten
  minutes. Pour custard on top of sponge. Chill in fridge. Whip cream until
  stiff and smooth over top of custard. Arrange almonds decoratively.

  NOTES:

  *  The title says it all -- This recipe is my own invention.

  : Difficulty:  moderate
  : Time:  1 hour preparation, 1 day waiting, 10 minutes cooking.
  : Precision:  no need to measure.

  : Angi Lamb
  : Department of Computer Science, University of York, UK
  : ukc!minster!angi

  : Copyright (C) 1986 USENET Community Trust

  From Gemini's MASSIVE MealMaster collection at www.synapse.com/~gemini

</step></directions></recipe></recipeml>

Upvotes: 1

Views: 345

Answers (3)

cwallenpoole
cwallenpoole

Reputation: 82018

DomDocument has a function JUST FOR THAT!

How to use getElementsByTagName:

$doc = new DOMDocument();
$doc->load(<xml>);
foreach( $doc->getElementsByTagName('ing') as $tag ) 
{
    // to iterate the children
    foreach( $tag->childNodes as $child ) 
    {
        // outputs the xml of the child nodes. Of course, there are any number of
        // things that you could do instead!
        echo $doc->saveXML($child);
    }
}

Upvotes: 1

Trey
Trey

Reputation: 5520

function unserialize_xml($input, $callback = null, $recurse = false){
    $data = ((!$recurse) && is_string($input))? simplexml_load_string($input): $input;
    if ($data instanceof SimpleXMLElement) $data = (array) $data;
    if (is_array($data)) foreach ($data as &$item) $item = unserialize_xml($item, $callback, true);
    return (!is_array($data) && is_callable($callback))? call_user_func($callback, $data): $data;
}

send the XML string to this function and check the results which are now an array which is easy to work with:

foreach($result['recipe'] as $recipe){
  echo $recipe['title'].' - '.count($recipe['ingredients']['ing']);
}

EDIT:

just add an iterator for your while loop

$xml = new DOMDocument();
$xml->load(path/to/file);
$xpath = new DOMXPath($xml);
$ingdiv = $xpath->query("/recipeml/recipe/ingredients/ing-div");
$length = $ingdiv->length;
$key=0;
// iterate over all <ing-div> from last to first
while($key<$length) {
 // number of <ing> in the specific <ing-div> 
  print $xpath->query("ing", $ingdiv->item($key))->length;
  $key++ 
}

Upvotes: 1

cEz
cEz

Reputation: 5062

Look at using Xpath with DOMXPath::query. You can then could the number of results produced by the query.

php > $doc = new DOMDocument();
php > $doc->preserveWhiteSpace = false;
php > $doc->Load("/tmp/test.xml");
php > $xpath = new DOMXPath($doc);
php > $query = "//ing";
php > $ingredients = $xpath->query($query);
php > echo $ingredients->length;
int(14)

You may need to modify the Xpath query to suit your needs.

Upvotes: 1

Related Questions