如何在保持当前属性的同时动态创建PHP SimpleXMLElement对象?

如何在保持当前属性的同时动态创建PHP SimpleXMLElement对象?,php,xml,object,Php,Xml,Object,我正在读取一个xml文件,该文件返回xml的SimpleXMLElement对象表示形式。我将获取一个数组并向该对象输入新值。我不知道我将在那个阵列中成为什么 如果我对这件事施加暴力,我会这样做 //Solution 1: Brute Force //Just creating an array and value for purposes of demonstration. $arOfData = array( [0]=>"theFirstNode", [1]=>

我正在读取一个xml文件,该文件返回xml的SimpleXMLElement对象表示形式。我将获取一个数组并向该对象输入新值。我不知道我将在那个阵列中成为什么

如果我对这件事施加暴力,我会这样做

//Solution 1: Brute Force

    //Just creating an array and value for purposes of demonstration.
    $arOfData = array( [0]=>"theFirstNode", [1]=>"theSecondNode",[2]=>"theThirdNode" );
    $value = "The XML Node Value";

    $simpleXml->$arOfData[0]->$arOfData[1]->$arOfData[2] = $value;

    //The next best thing I can think of doing is something like this.
    //Solution 2: Semi-brute force
    //
    foreach($this->arrayData as $key => $value) {
                $xmlNodes = explode( '-', $key);
                $numNodes = count($xmlNodes);
                switch($numNodes) {
                    case 1:
                        $simpleXml->$xmlNodes[0] = $value;
                        break;
                    case 2:
                        $simpleXml->$xmlNodes[0]->$xmlNodes[1] = $value;
                        break;
                    case 3:
                        $simpleXml->$xmlNodes[0]->$xmlNodes[1]->$xmlNodes[2] = $value;
                        break;
                    case 4:
                        $simpleXml->$xmlNodes[0]->$xmlNodes[1]->$xmlNodes[2]->$xmlNodes[3] = $value;
                        break;
                    case 5:
                        $simpleXml->$xmlNodes[0]->$xmlNodes[1]->$xmlNodes[2]->$xmlNodes[3]->$xmlNodes[4] = $value;
                        break;
                }
            }
*注意:此解决方案使用数组键并将其分解为由破折号分隔的数组,然后使用数组值作为新的xml值。所以不要让它分散你的注意力


解决方案#2的问题是:当我们得到一个深度超过5的xml节点时会发生什么?它不会被塞进我们正在创建的新对象中。噢。它也不是很优雅;)。我不知道如何以更递归的方式进行此操作。

就像您在问题中所写的那样,您需要动态地进行此操作,因为您不知道父元素的数量

您需要更深入地了解simpexml是如何完成这项工作的

但是首先让我建议你有一个不同的符号,不是用减号,而是用一条类似于路径的斜线

first/second/third
这在Xpath中也很常见,我认为它本身就是一个很好的例子。减号也可以是元素名的一部分,但斜杠不能。所以这只是稍微好一点

在我向您展示如何轻松访问
元素节点以设置其值之前,首先让我们看看simplexml中的一些赋值基础

要在SimpleXMLElement中访问和设置此元素节点,请参见以下示例:

$xml = new SimpleXMLElement('<root><first><second><third/></second></first></root>');    

$element = $xml->first->second->third;
$element[0] = "value";
因此,让我们尝试有条件地添加第三个元素,以防它不存在:

$xml = new SimpleXMLElement('<root><first><second/></first></root>');

$element = $xml->first->second->third;
var_dump($element[0]); # NULL
if ($xml->first->second->third[0] === NULL) {
    $xml->first->second->third = "";
}
这确实解决了这个问题。因此,唯一要做的就是以迭代方式对路径的所有部分执行此操作:

first/second/third
要使此操作简单,请为此创建一个函数:

/**
 * Modify an elements value specified by a string-path.
 *
 * @param SimpleXMLElement $parent
 * @param string           $path
 * @param string           $value (optional)
 *
 * @return SimpleXMLElement the modified element-node
 */
function simplexml_deep_set(SimpleXMLElement $parent, $path, $value = '') 
{
    ### <mocked> to be removed later: ###

    if ($parent->first->second->third[0] === NULL) {
        $parent->first->second->third = "";
    }

    $element = $parent->first->second->third;

    ### </mocked> ###

    $element[0] = $value;

    return $element;
}
这个foreach需要用一个工作版本替换mock。与完整的函数定义比较,一目了然:

function simplexml_deep_set(SimpleXMLElement $parent, $path, $value = '')
{
    $steps   = explode('/', $path);

    $element = $parent;
    foreach ($steps as $step)
    {
        if ($element->{$step}[0] === NULL) {
            $element->$step = "";
        }

        $element = $element->$step;
    }

    $element[0] = $value;

    return $element;
}
让我们修改更多疯狂的东西来测试它:

$xml = new SimpleXMLElement('<root><first><second/></first></root>');

simplexml_deep_set($xml, "first/second/third", "The XML Node Value");

simplexml_deep_set(
    $xml, "How/do/I/dynamically/create/a/php/simplexml/object/while/keeping/current/properties"
    , "The other XML Node Value"
);

$xml->asXML('php://output');
$xml=新的SimpleXMLElement(“”);
simplexml_deep_set($xml,“第一/第二/第三”,“xml节点值”);
simplexml\u深集(
$xml,“How/do/I/dynamicy/create/a/php/simplexml/object/while/keeping/current/properties”
,“另一个XML节点值”
);
$xml->asXML($xml)php://output');
示例输出(美化):


XML节点值

就像您在问题中所写的那样,您需要动态地使用它,因为您不知道父元素的数量

您需要更深入地了解simpexml是如何完成这项工作的

但是首先让我建议你有一个不同的符号,不是用减号,而是用一条类似于路径的斜线

first/second/third
这在Xpath中也很常见,我认为它本身就是一个很好的例子。减号也可以是元素名的一部分,但斜杠不能。所以这只是稍微好一点

在我向您展示如何轻松访问
元素节点以设置其值之前,首先让我们看看simplexml中的一些赋值基础

要在SimpleXMLElement中访问和设置此元素节点,请参见以下示例:

$xml = new SimpleXMLElement('<root><first><second><third/></second></first></root>');    

$element = $xml->first->second->third;
$element[0] = "value";
因此,让我们尝试有条件地添加第三个元素,以防它不存在:

$xml = new SimpleXMLElement('<root><first><second/></first></root>');

$element = $xml->first->second->third;
var_dump($element[0]); # NULL
if ($xml->first->second->third[0] === NULL) {
    $xml->first->second->third = "";
}
这确实解决了这个问题。因此,唯一要做的就是以迭代方式对路径的所有部分执行此操作:

first/second/third
要使此操作简单,请为此创建一个函数:

/**
 * Modify an elements value specified by a string-path.
 *
 * @param SimpleXMLElement $parent
 * @param string           $path
 * @param string           $value (optional)
 *
 * @return SimpleXMLElement the modified element-node
 */
function simplexml_deep_set(SimpleXMLElement $parent, $path, $value = '') 
{
    ### <mocked> to be removed later: ###

    if ($parent->first->second->third[0] === NULL) {
        $parent->first->second->third = "";
    }

    $element = $parent->first->second->third;

    ### </mocked> ###

    $element[0] = $value;

    return $element;
}
这个foreach需要用一个工作版本替换mock。与完整的函数定义比较,一目了然:

function simplexml_deep_set(SimpleXMLElement $parent, $path, $value = '')
{
    $steps   = explode('/', $path);

    $element = $parent;
    foreach ($steps as $step)
    {
        if ($element->{$step}[0] === NULL) {
            $element->$step = "";
        }

        $element = $element->$step;
    }

    $element[0] = $value;

    return $element;
}
让我们修改更多疯狂的东西来测试它:

$xml = new SimpleXMLElement('<root><first><second/></first></root>');

simplexml_deep_set($xml, "first/second/third", "The XML Node Value");

simplexml_deep_set(
    $xml, "How/do/I/dynamically/create/a/php/simplexml/object/while/keeping/current/properties"
    , "The other XML Node Value"
);

$xml->asXML('php://output');
$xml=新的SimpleXMLElement(“”);
simplexml_deep_set($xml,“第一/第二/第三”,“xml节点值”);
simplexml\u深集(
$xml,“How/do/I/dynamicy/create/a/php/simplexml/object/while/keeping/current/properties”
,“另一个XML节点值”
);
$xml->asXML($xml)php://output');
示例输出(美化):


XML节点值

由于斜杠的衍生方式,我无法使用这些斜杠,但我理解其好处。TyI理解,您只需要修改
explode()
行即可更改该行为,我想您可以处理它。如果没有,请告诉我——我将无法使用这些斜杠,因为它们是如何派生出来的,但我理解其好处。TyI理解,您只需要修改
explode()
行即可更改该行为,我想您可以处理它。如果没有,请告诉我-