【问题标题】:PHP - join elements with the same attribute within a loopPHP - 在循环中加入具有相同属性的元素
【发布时间】:2017-04-19 09:27:55
【问题描述】:

我正在尝试对 XML 中的元素进行“分组”,其中一些元素共享相同的日期,然后从这些元素“组”中打印某些值。

XML 结构:

<parent>

    <!-- Day 1 -->
    <element date="2017-04-18D12:00:00">
        <node value="30" />
        <node value="82" /> <!-- This is the highest of the day 1 -->
        <node value="25" />
        <foo name="noon" />
    </element>
    <element date="2017-04-18D18:00:00">
        <node value="12" />
        <node value="52" />
        <node value="11" /> <!-- This is the lowest of the day 1 -->
        <foo name="evening" />
    </element>

    <!-- Day 2 -->
    <element date="2017-04-19D00:00:00">
        <node value="21" />
        <node value="78" />
        <node value="33" />
        <foo name="night" />
    </element>
    <element date="2017-04-19D06:00:00">
        <node value="35" />
        <node value="57" />
        <node value="88" />
        <foo name="morning" />
    </element>
    <element date="2017-04-19D12:00:00">
        <node value="22" />
        <node value="92" /> <!-- This is the highest of the day 2 -->
        <node value="81" /> 
        <node value="19" />
        <foo name="noon" />
    </element>
    <element date="2017-04-19D18:00:00">
        <node value="2" /> <!-- This is the lowest of the day 2 -->
        <node value="30" />
        <node value="44" />
        <foo name="evening" />
    </element>

    <!-- Day 3 -->
    <element date="2017-04-20D00:00:00">
        <node value="12" />
        <node value="99" />
        <node value="43" />
        <foo name="night" />
    </element>
    <element date="2017-04-20D06:00:00">
        <node value="65" />
        <node value="211" /> <!-- This is the highest of the day 3 -->
        <node value="16" />
        <foo name="morning" />
    </element>
    <element date="2017-04-20D12:00:00">
        <node value="32" />
        <node value="55" />
        <node value="77" /> 
        <node value="1" /> <!-- This is the lowest of the day 3 -->
        <foo name="noon" />
    </element>
    <element date="2017-04-20D18:00:00">
        <node value="68" />
        <node value="74" />
        <node value="21" />
        <foo name="evening" />
    </element>
    ...
</parent>

每个元素都有一个日期属性,我想用它来对元素进行分组。

应打印最终结果

<div class="group">
    <div>Monday</div>
    <div>11</div>
    <div>82</div>
    <div>noon</div>
    <div>evening</div>
</div>
<div class="group">
    <div>Thursday</div>
    <div>2</div>
    <div>92</div>
    <div>night</div>
    <div>morning</div>
    <div>noon</div>
    <div>evening</div>
</div>
<div class="group">
    <div>Wednesday</div>
    <div>1</div>
    <div>211</div>
    <div>night</div>
    <div>morning</div>
    <div>noon</div>
    <div>evening</div>
</div>
...

这是我目前所拥有的:

$source = simplexml_load_file('http://example.com');
foreach ($source -> parent -> element as $element) {
    // Format the date value and get the day so the elements could group
    $from      = explode('D', $element['date']);
    $group_day = explode('-', trim($from[0]));

    // problem starts here :)

}

XML 中的注释仅用于演示,不包含在其中。

【问题讨论】:

    标签: php xml foreach


    【解决方案1】:

    这是一种比 last time 更好的 XML 格式,因为它更容易关联元素。

    像上次一样,让我们​​解析 XML 并将其放入我们可以使用的格式。

    我们将创建另一个关联映射$groups,但这次键入来自&lt;element/&gt; 日期属性的日期。由于我们需要存储一天中的时间,我们需要调整地图的值,以便我们可以存储&lt;node/&gt; 值属性和&lt;foo/&gt; 名称属性。这可以通过制作内部地图轻松完成。

    $xml = simplexml_load_file('http://example.com');
    
    // group all the value/name attributes
    
    foreach ($xml->element as $element) {
        $datetime = (string) $element->attributes()['date'];
        // let's remove the time
        $date = substr($datetime, 0, 10);
        // check if there is a group for that date; if not create one
        if (!isset($groups[$date])) {
            $groups[$date] = [];
            // this will be used to store all the value attributes for this date
            $groups[$date]['values'] = []; 
            // this will be used to store all the name attributes for this date
            $groups[$date]['names'] = [];
        }
        // store the next value attributes in that group
        foreach ($element->node as $node) {
            $groups[$date]['values'][] = (int) $node->attributes()['value'];
        }
        // store the next name attributes in that group
        foreach ($element->foo as $foo) {
            $groups[$date]['names'][] = (string) $foo->attributes()['name'];
        }
    }
    
    // now we have everything we need to build the result
    
    foreach ($groups as $date => $group) {
        print '<div class="group">';
        printf('<div>%s</div>', date('l', strtotime($date)));
        printf('<div>%d</div>', min($group['values']));
        printf('<div>%d</div>', max($group['values']));
        foreach ($group['names'] as $name) {
            printf('<div>%s</div>', $name);
        }
        print '</div>';
    }
    

    【讨论】:

    • 这非常有效 - 感谢您的详细解释,有不少 AHA 时刻。希望我可以多次投票:)
    【解决方案2】:

    试试这个希望它会帮助你。在这里,我使用DOMDocument 来检索名称为element 的标签,然后检索其属性date,然后你可以做你想做的事..

    Try this code snippet here

    $source = new DOMDocument();
    $source->loadXML('<parent>
    
        <!-- Day 1 -->
        <element date="2017-04-18D12:00:00">
            <node value="30" />
            <node value="82" /> <!-- This is the highest of the day 1 -->
            <node value="25" />
            <foo name="noon" />
        </element>
        <element date="2017-04-18D18:00:00">
            <node value="12" />
            <node value="52" />
            <node value="11" /> <!-- This is the lowest of the day 1 -->
            <foo name="evening" />
        </element>
    
        <!-- Day 2 -->
        <element date="2017-04-19D00:00:00">
            <node value="21" />
            <node value="78" />
            <node value="33" />
            <foo name="night" />
        </element>
        <element date="2017-04-19D06:00:00">
            <node value="35" />
            <node value="57" />
            <node value="88" />
            <foo name="morning" />
        </element>
        <element date="2017-04-19D12:00:00">
            <node value="22" />
            <node value="92" /> <!-- This is the highest of the day 2 -->
            <node value="81" /> 
            <node value="19" />
            <foo name="noon" />
        </element>
        <element date="2017-04-19D18:00:00">
            <node value="2" /> <!-- This is the lowest of the day 2 -->
            <node value="30" />
            <node value="44" />
            <foo name="evening" />
        </element>
    
        <!-- Day 3 -->
        <element date="2017-04-20D00:00:00">
            <node value="12" />
            <node value="99" />
            <node value="43" />
            <foo name="night" />
        </element>
        <element date="2017-04-20D06:00:00">
            <node value="65" />
            <node value="211" /> <!-- This is the highest of the day 3 -->
            <node value="16" />
            <foo name="morning" />
        </element>
        <element date="2017-04-20D12:00:00">
            <node value="32" />
            <node value="55" />
            <node value="77" /> 
            <node value="1" /> <!-- This is the lowest of the day 3 -->
            <foo name="noon" />
        </element>
        <element date="2017-04-20D18:00:00">
            <node value="68" />
            <node value="74" />
            <node value="21" />
            <foo name="evening" />
        </element>
    </parent>');
    $result=array();
    foreach ($source->getElementsByTagName("element") as $element)
    {
        $date=$element->getAttribute("date");
        $from      = explode('D', $date);
        $group_day = explode('-', trim($from[0]));
        $values=array();
        $weekDay=date("l",  strtotime($date));
        foreach($element->childNodes as $node)
        {
            if($node instanceof DOMElement)
            {
                if(!empty($node->getAttribute("value")))
                {
                    $result[$group_day[2]]["values"][]=$node->getAttribute("value");
                }
                else
                {
                    $result[$group_day[2]]["datetime"][]=$node->getAttribute("name");
                }
            }
        }
        $result[$group_day[2]]["weekDay"][$weekDay]=$weekDay;
    }
    
    foreach($result as $key => $value)
    {
        $array=$result[$key]["values"];
        asort($array);
        $lowest=$array[key($array)];
        arsort($array);
        $highest=$array[key($array)];
        $result[$key]["values"]=array();
        $result[$key]["values"]["highest"]=$highest;
        $result[$key]["values"]["lowest"]=$lowest;
    }
    print_r($result);
    

    【讨论】:

    • 我已经获得了属性并设置了日期的格式以得出日期。我要做的是在同一天对元素进行“分组”,并从整个“组”中提取最小/最大节点值,并显示当前“组”中每个元素的名称值。
    • @g5wx 你想按天对元素进行分组吗?
    • 也谢谢你的回答,也很好用,但我想我现在会使用 Mikey 的解决方案。再次感谢,点赞!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-03
    • 2018-12-12
    • 2011-06-11
    • 1970-01-01
    • 1970-01-01
    • 2020-05-03
    • 1970-01-01
    相关资源
    最近更新 更多