1

I'm trying to get the maximum and the minimum value of the option-node for each item in the following xml (snippet):

<body>
    <page number="1">
        <itemset name="a">
            <item id="1">
               <option value="0">no</option>
               <option value="1">rarely</option>
               <option value="3">sometimes</option>
               <option value="5">often</option>
               <scale id="ho" />
            </item>
            <item id="2">
                <option value="0">no</option>
                <option value="1">rarely</option>
                <option value="3">sometimes</option>
                <option value="5">often</option>
                <scale id="hi" />
            </item>
        </itemset>
    </page>
</body>

I'm doing this within a foreach-loop...

...

$scid="ho";
$total=0;
$count=0;

foreach ($txml->xpath("//item[scale/@id='$scid']") as $item) {
    $score=$rxml->xpath("//item[@id='".$item['id']."']"); // get a value from another simple_xml-object
$total+=intval($score[0]);
$count++;
// ******* problem starts here...           
$values = $item->option['value'];
// doing sth with $values to get max and min value
    echo '<pre>'; 
    print_r($values); // ******* 
    echo '</pre>';
} // foreach $item

...

What I get in $values is

SimpleXMLElement Object
(
    [0] => 0
)

with $values = $item->xpath('option[@value]'); instead, I get...

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

    )

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

    )

    [2] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [value] => 3
            )

    )

    [3] => SimpleXMLElement Object
    (
        [@attributes] => Array
            (
                [value] => 5
            )

    )

)

I am looking for a more straightforward solution - or how to get min and max from there.

I'd like to get sth like $values['max']=5 and $values['min']=0

Thank you in advance,

Michi

PS: as I wasn't able to get this working with simple_xml and didn't want to switch to DOM, I decided to do it quick and dirty with some basic PHP:

foreach ($item->xpath("//item[@id='".$item['id']."']/option/@value") as $value) {
    $v[]=(int)$value->value;
}
echo max($v);
echo min($v);
michi
  • 6,565
  • 4
  • 33
  • 56
  • 1
    What's the expected output when running on your example XML? By the way, your XML is broken. – Jens Erat Feb 08 '13 at 18:41
  • desired output see edit in post. the xml is a snippet, the original file is ok. – michi Feb 08 '13 at 18:53
  • @michi You'll find answers here : http://stackoverflow.com/questions/1128745/how-can-i-use-xpath-to-find-the-minimum-value-of-an-attribute-in-a-set-of-elemen – hek2mgl Feb 08 '13 at 19:05
  • 1
    Answers in that link are fine, you'll have to use the XPath 1.0 solutions as SimpleXML doesn't support XPath 2.0. – Jens Erat Feb 08 '13 at 19:23
  • @hek2mgl tried to translate it for my case, but failed --> xPath() invalid expression. used `/option/@value[not(. < ../option/@value)][1]` and variations. Hints appreciated! – michi Feb 08 '13 at 19:59
  • @Ranon: good point, but can't figure out the syntax for my file :-( tried also `/item/option/@value[not(. < ../../option/@value)][1]` --> invalid expression. Any suggestions? – michi Feb 08 '13 at 20:03
  • I see. I can't get it working too – hek2mgl Feb 08 '13 at 20:26
  • `<` should be `<`, whatever went wrong there... EDIT: fixed the two answers with entities instead of operators. – Jens Erat Feb 08 '13 at 20:36
  • @Ranon I see your edit on the answers in the post I've linked above. **Have you tested this**? This will not work. Also note that I expect the other post is xslt related. Your edit would lead to a syntax error! **Please be careful before doing such edits**. I would rollback this if I where you. – hek2mgl Feb 08 '13 at 20:43
  • @ranon ok, no more error, but no result yet, tried `/option/@value[not(. < ../option/@value)][1]` and got an empty array... ideas? Thx! – michi Feb 08 '13 at 20:46
  • @hek2mgl gets `(bool)false`... – michi Feb 08 '13 at 21:12
  • @michi, I got errors. Are you working with windows? – hek2mgl Feb 08 '13 at 21:13
  • @hek2mgl I'm totally sure about these edits, and using entities as operators is just plain wrong. Have a look at [w3c's XPath definition](http://www.w3.org/TR/xpath/#booleans) or simply throw these queries into some engine of your choice. – Jens Erat Feb 08 '13 at 21:36
  • @Ranon Yes, I'll test it with xsl. But I cannot really imagine that this will work. Note that HTML with = – hek2mgl Feb 08 '13 at 21:40
  • @hek2mgl MAMP/Mac PHP 5.4.4 – michi Feb 08 '13 at 21:45
  • 1
    @hek2mgl: Sorted it out, the question is about ant scripts. I added some hint to add these entities if using in XML files, but kept `<`/`>` in the answers as these are all about XPath where the entities would be plain wrong and obviously confuse people. Think we shold stop that offtopic discussion in here, sent you an email. – Jens Erat Feb 08 '13 at 21:57
  • @Ranon I've investigated it with `xmllint --xpath` and `xsltproc` on the linux command line, and yes it worked with both. `<` and `<` PHP (libxml2) seems to be the only language than doesn't understand the `<`. However xmllint will at least replace the `<` by `<` meaning that it looks 'better' to it. We'll see if someone will cry because of your edits. ;) – hek2mgl Feb 08 '13 at 22:05
  • @michi. I forgot that you are using simple_xml. Thats why `libxml_get_last_error()` returned `false`. My bad. – hek2mgl Feb 08 '13 at 22:15
  • @Ranon Update: check this example. http://pastebin.com/QPnUDFUq Save it as test.xml and open it in a browser. Its broken, not well formed. Do you believe me now? – hek2mgl Feb 08 '13 at 22:20
  • This is XSLT, not bare plain XPath. For sure you have to use entities in here, but that posts aren't about XSLT. Still propose switching to email. – Jens Erat Feb 08 '13 at 22:42

1 Answers1

0

With help of this post I got the following example working:

$doc = new DOMDocument();
@$doc->loadHTML($htmlcontent);

$selector = new DOMXPath($doc);

// get max value of item with id 1
$result = $selector->query('//item[@id=1]/option[not(preceding-sibling::option/@value >= @value) and not(following-sibling::option/@value > @value)]/@value');

if(!$result || $result->length < 1) {
    die('error');
}
foreach($result as $item) {
    echo 'max: ', $result->item(0)->value, PHP_EOL;
}


// get min value of item with id 1
$result = $selector->query('//item[@id=1]/option[not(preceding-sibling::option/@value <= @value) and not(following-sibling::option/@value < @value)]/@value');

if(!$result || $result->length < 1) {
    die('error');
}
foreach($result as $item) {
    echo 'min: ' . $result->item(0)->value, PHP_EOL;
}
Community
  • 1
  • 1
hek2mgl
  • 152,036
  • 28
  • 249
  • 266