如何在保持当前属性的同时动态创建PHP SimpleXMLElement对象?
我正在读取一个xml文件,该文件返回xml的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]=>
//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()
行即可更改该行为,我想您可以处理它。如果没有,请告诉我-