首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用数组更新SimpleXMLElement

如何使用数组更新SimpleXMLElement
EN

Stack Overflow用户
提问于 2013-02-13 00:15:31
回答 2查看 396关注 0票数 1

我有一个适用于Flash编码器的xml:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<flashmedialiveencoder_profile>
    <preset>
        <name></name>
        <description></description>
    </preset>
    <capture>
        <video>
            <device></device> 
            <crossbar_input>1</crossbar_input>
            <frame_rate>25.00</frame_rate>
            <size>
                <width></width>
                <height></height>
            </size>
        </video>
        <audio>
            <device></device> 
            <crossbar_input>2</crossbar_input>
            <sample_rate></sample_rate>
            <channels>1</channels>
            <input_volume>60</input_volume>
        </audio>
    </capture>
    <encode>
        <video>
            <format>H.264</format>
            <datarate></datarate>
            <outputsize></outputsize>
            <advanced>
                <profile></profile>
                <level></level>
                <keyframe_frequency>5 Seconds</keyframe_frequency>
            </advanced>
            <autoadjust>
                <enable>false</enable>
                <maxbuffersize>1</maxbuffersize>
                <dropframes>
                <enable>false</enable>
                </dropframes>
                <degradequality>
                <enable>false</enable>
                <minvideobitrate></minvideobitrate>
                <preservepfq>false</preservepfq>
                </degradequality>
            </autoadjust>
        </video>
        <audio>
            <format>MP3</format>
            <datarate></datarate>
        </audio>
    </encode>
    <restartinterval>
        <days></days>
        <hours></hours>
        <minutes></minutes>
    </restartinterval>
    <reconnectinterval>
        <attempts></attempts>
        <interval></interval>
    </reconnectinterval>
    <output>
        <rtmp>
        <url></url>
        <backup_url></backup_url>
        <stream></stream>
        </rtmp>
    </output>
    <metadata>
        <entry>
        <key>author</key>
        <value></value>
        </entry>
        <entry>
        <key>copyright</key>
        <value></value>
        </entry>
        <entry>
        <key>description</key>
        <value></value>
        </entry>
        <entry>
        <key>keywords</key>
        <value></value>
        </entry>
        <entry>
        <key>rating</key>
        <value></value>
        </entry>
        <entry>
        <key>title</key>
        <value></value>
        </entry>
    </metadata>
    <preview>
        <video>
        <input>
            <zoom>50%</zoom>
        </input>
        <output>
            <zoom>50%</zoom>
        </output>
        </video>
        <audio></audio>
    </preview>
    <log>
        <level>100</level>
        <directory></directory>
    </log>
</flashmedialiveencoder_profile>

我需要根据用户需要的xml类型更新一些数据。所以我想做这样的事情:

代码语言:javascript
复制
$data = array (
    'preset' => array (
        'name' => 'Low Bandwidth (150 Kbps) - H.264',
    ),
    'capture' => array (
        'audio'  => array (
            'sample_rate' => 44100
        )
    ),
    'encode' => array (
        'video' => array (
            'datarate' => '300;',
            'outputsize' => '480x360;',
            'advanced' => array (
                'profile' => 'Main',
                'level' => 2.1,
            )
         ),
         'audio' => array (
            'datarate' => 48
         )
    ),
);

我知道这棵树很有效,因为我可以手动完成,但问题是我不想这样做,所以如果将来我需要更改xml中的其他想法,我只需将其添加到数组配置中。

我该怎么做呢?我可以写一个递归函数来做这件事,但我真的不想这样做。还有没有别的办法呢?我不知道。可能是这样的:

代码语言:javascript
复制
$xml->updateFromArray($data);

我重复一遍,我可以编写该函数并扩展SimpleXMLElement,但如果有其他原生php方法可以做到这一点,那就更好了。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-02-13 02:29:32

考虑到$xml是作为SimpleXMLElement的文档元素,而$data是您的数组(如问题中所述),如果您关心对子元素进行编号,例如对元数据进行编号,我会将其在数组中按如下方式编号:

代码语言:javascript
复制
'metadata' => array(
    'entry' => array(
        5 => array(
            'value' => 'Sunny Days',
        ),
    ),
),

下面是通过堆栈以非递归的方式解决问题的方法:

代码语言:javascript
复制
while (list($set, $node) = array_pop($stack)) {
    if (!is_array($set)) {
        $node[0] = $set;
        continue;
    }

    foreach ($set as $element => $value) {
        $parent = $node->$element;
        if ($parent[0] == NULL) {
            throw new Exception(sprintf("Child-Element '%s' not found.", $element));
        }
        $stack[] = array($value, $parent);
    }
}

一些注意事项:

  • I更改了具体的异常类型以删除dependency.
  • $parent[0] == NULL测试元素$parent不为空(比较/查看SimpleXML Type Cheatsheet).
  • As元素节点被放入堆栈中以备稍后检索,从堆栈获取后需要使用$node[0]来设置它(编号的元素已经在$node中(默认情况下是第一个),以后要更改它,需要使用0作为偏移量)。

还有Online Demo

到目前为止,这个示例不允许创建新的元素,如果它们目前还不存在。要添加添加新元素,则会为不存在的子级抛出异常:

代码语言:javascript
复制
        if ($parent[0] == NULL) {
            throw new Exception(sprintf("Child-Element '%s' not found.", $element));
        }

需要替换为添加新的子代的代码,包括第一个:

代码语言:javascript
复制
        if ($parent[0] == NULL) {
            if (is_int($element)) {
                if ($element != $node->count()) {
                    throw new Exception(sprintf("Element Number out of order: %d unfitting for %d elements so far.", $element, $node->count()));
                }
                $node[] = '';
                $parent = $node->$element;
            } else {
                $parent[0] = $node->addChild($element);
            }
        }

仍然存在的例外情况是添加了一个新元素,但它的数量大于现有元素数量加1。例如,你有4个元素,然后你“添加”了数字为6的元素,这是行不通的。该值是从零开始的,这通常不会有任何问题。

Demo

票数 2
EN

Stack Overflow用户

发布于 2013-02-13 00:32:46

我已经让这个对象扩展了SimpleXMLElement,但是如果有更好的方法,我将非常感谢:)

代码语言:javascript
复制
/**
 * Object to manipulate and add information to an xml object
 *
 * @package Stream
 * @subpackage SimpleXMLElement
 * @author abraham.sustaita@gmail.com
 * @author Abraham Cruz
 * @version 2 Added functionality to update data with array 
 * @example $this->rows[0] = array (); now can be edited
 */
class Stream_SimpleXMLElement extends SimpleXMLElement 
{
    /** 
     * Method to update the information of the xml
     * from an array
     * 
     * @throws Core_Exception
     * @param array $array
     * @return Stream_SimpleXMLElement
     */
    public function updateFromArray(array $array) {
        foreach ($array as $key => $data) {
            if ($this->$key->count() == 0) {
                throw new Core_Exception("The key {$key} does not exists within the XML object.");
            } else if ($this->$key->count() > 1) {
                foreach ($data as $i => $value) {
                    $tmpData = &$this->$key;
                    $tmpkey = &$tmpData [$i];
                    if (is_array($value)) {
                        foreach ($value as $key2 => $value2) {
                            if ($tmpkey->$key2 instanceof Stream_SimpleXMLElement && is_array($value2)) {
                                $tmpkey->$key2->updateFromArray($value2);
                            } else {
                                $tmpkey->$key2 = $value2;
                            }
                        }
                    } else {
                        $tmpkey = $value;
                    }
                    unset ($tmpData, $tmpkey);
                }
            } else {
                if (is_array($data)) {
                    $this->$key->updateFromArray($data);
                } else {
                    $this->$key = $data;
                }
            }
        }
        return $this;
    }
}

由于object Stream_SimpleXMLElement扩展了SimpleXMLElement,因此该对象的每个子对象都将是Stream_SimpleXMLElement的实例,因此我们可以使用相同的方法...

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14836849

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档