SimpleXMLElement 类

(PHP 5, PHP 7, PHP 8)

简介

表示 XML 文档中的一个元素。

类概要

class SimpleXMLElement implements Stringable, Countable, RecursiveIterator {
/* 方法 */
public __construct(
    string $data,
    int $options = 0,
    bool $dataIsURL = false,
    string $namespaceOrPrefix = "",
    bool $isPrefix = false
)
public addAttribute(string $qualifiedName, string $value, ?string $namespace = null): void
public addChild(string $qualifiedName, ?string $value = null, ?string $namespace = null): ?SimpleXMLElement
public asXML(?string $filename = null): string|bool
public attributes(?string $namespaceOrPrefix = null, bool $isPrefix = false): ?SimpleXMLElement
public children(?string $namespaceOrPrefix = null, bool $isPrefix = false): ?SimpleXMLElement
public count(): int
public getDocNamespaces(bool $recursive = false, bool $fromRoot = true): array|false
public getName(): string
public getNamespaces(bool $recursive = false): array
public hasChildren(): bool
public key(): string
public next(): void
public registerXPathNamespace(string $prefix, string $namespace): bool
public rewind(): void
public __toString(): string
public valid(): bool
public xpath(string $expression): array|null|false
}

变更日志

版本 描述
8.0.0 SimpleXMLElement 现在实现了 StringableCountableRecursiveIterator

目录

添加注释

用户贡献的注释 28 个注释

188
rmirabelle
13 年前
为了进一步说明之前的评论并强调重点

使 SimpleXMLElement 难以使用的原因是它看起来和行为都像一个对象,但实际上是一个系统资源(具体来说是一个 libxml 资源)。

这就是为什么你不能将 SimpleXMLElement 存储到 $_SESSION 中,或者在不先将节点值强制转换为某种类型的对象的情况下对节点值执行直接比较操作。$_SESSION 期望存储“一个对象”,而比较运算符期望比较 2 个“对象”,而 SimpleXMLElements 不是对象。

当你回显或打印节点的值时,PHP 会为你将值(一个资源)转换为字符串对象。这确实省时,但会让你误以为你的 SimpleXMLElement 是一个对象。

希望这有助于澄清
70
juanfhj at gmail dot spam dot me dot not dot com
13 年前
要将底层元素作为字符串访问,需要进行强制转换 $x = (string)$my_xml_element。
26
CameronXie
6 年前
将 xml 映射到数组(包含属性)

<?php declare(strict_types=1);

/**
* @param SimpleXMLElement $xml
* @return array
*/
function xmlToArray(SimpleXMLElement $xml): array
{
$parser = function (SimpleXMLElement $xml, array $collection = []) use (&$parser) {
$nodes = $xml->children();
$attributes = $xml->attributes();

if (
0 !== count($attributes)) {
foreach (
$attributes as $attrName => $attrValue) {
$collection['attributes'][$attrName] = strval($attrValue);
}
}

if (
0 === $nodes->count()) {
$collection['value'] = strval($xml);
return
$collection;
}

foreach (
$nodes as $nodeName => $nodeValue) {
if (
count($nodeValue->xpath('../' . $nodeName)) < 2) {
$collection[$nodeName] = $parser($nodeValue);
continue;
}

$collection[$nodeName][] = $parser($nodeValue);
}

return
$collection;
};

return [
$xml->getName() => $parser($xml)
];
}
37
Anonymous
12 年前
警告任何尝试解析键名包含连字符的 XML 的人,例如:)
<subscribe>
<callback-url>example url</callback-url>
</subscribe>

为了访问 callback-url,你需要执行以下操作
<?php
$xml
= simplexml_load_string($input);
$callback = $xml->{"callback-url"};
?>
如果你尝试在没有花括号和引号的情况下执行,你会发现返回的是 0 而不是你想要的结果。
16
saganmarketing.com
12 年前
通过 SimpleXML 解析无效的 XML 字符串会导致脚本完全崩溃(通常情况下),因此最好在使用 SimpleXML 解析之前确保 XML 的有效性,可以使用类似以下代码:

// 必须使用 === 测试,例如 if(isXML($xml) === true){}
// 返回错误消息,如果 XML 不正确
function isXML($xml){
libxml_use_internal_errors(true);

$doc = new DOMDocument('1.0', 'utf-8');
$doc->loadXML($xml);

$errors = libxml_get_errors();

if(empty($errors)){
return true;
}

$error = $errors[0];
if($error->level < 3){
return true;
}

$explodedxml = explode("r", $xml);
$badxml = $explodedxml[($error->line)-1];

$message = $error->message . ' at line ' . $error->line . '. Bad XML: ' . htmlentities($badxml);
return $message;
}
9
php at keith tyler dot com
14 年前
输入 XML 字符串的根节点元素不可作为属性获取。

<?php
$xml
="<foo>bar</foo>";
$sxe=new SimpleXMLElement($xml);
print
$sxe->foo;
?>

不打印任何内容。你只能通过数组索引方法 ($sxe[0]) 访问根元素。

另外,你不能有两个(或更多)根元素——这显然不是格式良好的 XML。

<?php
$xml
="<foo/><bar/>";
$sxe=new SimpleXMLElement($xml);
?>

抛出异常。一个快速解决方案是在输入的两端追加一个任意根节点结构

<?php
$xml
="<foo/><bar/>";
$sxe=new SimpleXMLElement("<z>".$xml."</z>");
?>

这样做也解决了上面提到的根节点属性可访问性问题。(如果你的 XML 字符串包含声明,则可能不起作用。)
5
cherubangel at gmail dot com
14 年前
请注意,在 foreach 循环中更改属性,尤其是命名空间属性,可能会非常棘手。

例如,当尝试更改现有 xlink:href 属性的值时
<?php
foreach($xmlelement -> attributes('xlink', true) as $attribute => $attribvalue){
$attribvalue[0] = 'value'; // 抛出错误
$attribvalue = 'value'; // 不会更改你的 XML
$xmlelement -> addAttribute($attribute, 'value', 'http://www.w3.org/1999/xlink'); // 添加属性,不会更改现有属性。
$xmlelement[$attribute] = 'value'; // 添加属性,不会更改现有属性。
}
?>

相反,你应该直接访问 attributes() 函数返回的数组,如下所示
<?php
$xmlelement
-> attributes('xlink', true) -> href = 'value'; // 可行!
?>
13
heaver
12 年前
将 XML 转换为 JSON,不含“@attributes”
<?php
function XML2JSON($xml) {

function
normalizeSimpleXML($obj, &$result) {
$data = $obj;
if (
is_object($data)) {
$data = get_object_vars($data);
}
if (
is_array($data)) {
foreach (
$data as $key => $value) {
$res = null;
normalizeSimpleXML($value, $res);
if ((
$key == '@attributes') && ($key)) {
$result = $res;
} else {
$result[$key] = $res;
}
}
} else {
$result = $data;
}
}
normalizeSimpleXML(simplexml_load_string($xml), $result);
return
json_encode($result);
}
?>
6
brett at brettbrewer dot com
14 年前
弄清楚如何访问 SimpleXmlElement 对象的属性对我来说有点棘手。特别地,我花了一些时间才发现我需要将我的 SimpleXmlElement 属性转换为“字符串”类型才能打印它们或对它们进行比较。例如,假设你已经有一个字符串形式的 xml 在 $xmlstr 中...

<?php
$sxml
= new SimpleXmlElement($xmlstr);

if ((string)
$sxml->property== "somevalue") {
echo (string)
$sxml->property;
}
?>
SimpleXmlElement 对象的属性本身也是对象,所以你需要在它们之前加上“(string)”,这会将它们的值转换为字符串而不是对象。我假设如果你要进行数值比较,你需要转换为 (int) 或其他数字类型。
4
ivandosreisandrade at gmail dot com
14 年前
您好,

以下是我的贡献,帮助那些正在努力理解 SimpleXMLElement 如何工作的用户。

在尝试弄清楚它是如何工作的之后,我创建了这个小示例

<?php
$xmlstr
= "<?xml version='1.0' ?>\n".
// 可选地,你可以指定一个 xml-stylesheet 用于呈现结果。只需取消以下行的注释并更改样式表名称。
/* "<?xml-stylesheet type='text/xsl' href='xml_style.xsl' ?>\n". */
"<book></book>";

// 使用空的 <book> 元素创建 SimpleXMLElement 对象
$xml = new SimpleXMLElement($xmlstr);

// 添加一些子节点
$xml->addChild("title", "Title of my book");
$xml->addChild("abstract", "My book is about learning to work with SimpleXMLElement");

// 添加更多子节点
$chapter1 = $xml->addChild("chapter_1");
// 为子节点 chapter_1 添加属性
$chapter1->addAttribute("chapter_title", "Introduction to my book");

$chapter2 = $xml->addChild("chapter_2");
$chapter2->addAttribute("chapter_title", "Development of my book");

$chapter3 = $xml->addChild("chapter_3");
$chapter3->addAttribute("chapter_title", "Another chapter of my book");

$conclusion = $xml->addChild("conclusion", "The ending of my book");

// 插入标题以告诉浏览器如何读取文档
header("Content-type: text/xml");
// 打印 SimpleXMLElement 作为格式良好的 XML 字符串
echo $xml->asXML();
?>

你可以直接复制粘贴这段代码并尝试理解它的工作原理。
希望它能帮助到一些人 :)
3
francs at seznam dot cz
13 年前
当你尝试将某个属性转换为布尔值时,请注意。

(boolean)$xml->attributes()->someAtt;

如果属性是数组([0] => 0),则返回 TRUE;

请使用 (boolean)(int) 代替。
2
triplepoint at gmail dot com
14 年前
有时需要向 SimpleXMLElement 添加 XML 处理指令(将其视为完整文档)。
<?php
class SimpleXMLElement_Plus extends SimpleXMLElement {

public function
addProcessingInstruction( $name, $value )
{
// 从这个 simpleXML 对象创建一个 DomElement
$dom_sxe = dom_import_simplexml($this);

// 创建一个指向此 xml 的所有者文档的句柄
$dom_parent = $dom_sxe->ownerDocument;

// 查找 domDocument 中的最顶层元素
$xpath = new DOMXPath($dom_parent);
$first_element = $xpath->evaluate('/*[1]')->item(0);

// 在最顶层元素之前添加处理指令
$pi = $dom_parent->createProcessingInstruction($name, $value);
$dom_parent->insertBefore($pi, $first_element);
}
}
?>

例如,如果你有一个由以下 xml 片段组成的 SimpleXMLElement_Plus 对象
<xml><content /></xml>

并且你需要输出以下内容
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="xsl/xsl.xsl"?>
<xml><content/></xml>

你可以执行以下操作(使用上面的类):
<?php
$xml
= new SimpleXMLElement_Plus('<xml><content /></xml>');
$xml->addProcessingInstruction('xml-stylesheet', 'type="text/xsl" href="xsl/xsl.xsl"');
echo
$xml->asXML();
?>
2
frame at dynamiccreated dot de
11 年前
在文档中缺少的重要说明

SimpleXML 支持数组/迭代方法。因此,你可以

添加属性
编辑属性
删除属性

添加节点
编辑节点
删除节点

这就是 SimpleXML 仅提供添加方法而不提供删除或编辑方法的原因。我们还需要这些方法,因为 SimpleXML 充当普通类,并且
新的成员不会转换为新的节点。

在 foreach 循环中似乎无法删除节点。原因很简单。要做到这一点,我们需要一个有效的键,但是迭代器只给我们一个“可理解的反馈”关于我们正在处理的节点:标签名称。

所以这将不起作用

<?php
foreach($doc->seg as $key => $seg)
{
if((string)
$seg['id'] === 'whatever')
{
unset(
$seg); // 只清除本地副本
unset($seg[$key]); // 错误索引 "seg"
}
}
?>

但是这将起作用,例如
<?php
unset($doc->seg[2]);
?>

如有疑问,请始终使用 print_r/var_dump()。它将很好地显示真正的链接索引。
1
demian dot katz at villanova dot edu
12 年前
这是一个更具命名空间意识的版本,用于将一个 SimpleXMLElement 附加到另一个。我相信它仍然可以进一步改进(目前它生成了一些冗余的 xmlns 定义),但它似乎足够好地满足了我的目的。

function SimpleXMLElement_append($parent, $child)
{
// 获取文档的所有命名空间
$namespaces = $child->getNamespaces(true);

// 检查当前节点是否存在默认命名空间
$currentNs = $child->getNamespaces();
$defaultNs = count($currentNs) > 0 ? current($currentNs) : null;
$prefix = (count($currentNs) > 0) ? current(array_keys($currentNs)) : '';
$childName = strlen($prefix) > 1
? $prefix . ':' . $child->getName() : $child->getName();

// 检查值是否为字符串值/数据
if (trim((string) $child) == '') {
$element = $parent->addChild($childName, null, $defaultNs);
} else {
$element = $parent->addChild(
$childName, htmlspecialchars((string)$child), $defaultNs
);
}

foreach ($child->attributes() as $attKey => $attValue) {
$element->addAttribute($attKey, $attValue);
}
foreach ($namespaces as $nskey => $nsurl) {
foreach ($child->attributes($nsurl) as $attKey => $attValue) {
$element->addAttribute($nskey . ':' . $attKey, $attValue, $nsurl);
}
}

// 添加子节点 -- 首先尝试使用命名空间,但如果未找到命名空间子节点,则默认添加所有子节点。
// 如果没有找到命名空间子节点。
$children = 0;
foreach ($namespaces as $nskey => $nsurl) {
foreach ($child->children($nsurl) as $currChild) {
SimpleXMLElement_append($element, $currChild);
$children++;
}
}
if ($children == 0) {
foreach ($child->children() as $currChild) {
SimpleXMLElement_append($element, $currChild);
}
}
}
1
joshduck at gmail dot com
13 年前
如果你打算使用加法、乘法等操作,应该将元素转换为浮点数(甚至字符串)。如果你不这样做,PHP 会错误地将节点值视为整数。

<?php
$obj
= new SimpleXMLElement('<root>
<a>1.9</a>
<b>1.9</b>
</root>'
);

var_dump($obj->a + $obj->b);
var_dump((float)$obj->a + (float)$obj->b);
var_dump((string)$obj->a + (string)$obj->b);
?>

第一行输出:int(2)
第二行和第三行输出预期结果:float(3.8)
0
ohcc at 163 dot com
1 年前
你可以使用 PHP 的 unset() 语言结构删除 SimpleXMLElement 节点。

<?php
$xml
= <<<'EOT'
<users>
<user>
<name>orange</name>
<sex>male</sex>
<homepage>wuxiancheng.cn</homepage>
</user>
<user>
<name>tangerine</name>
<sex>male</sex>
<homepage>51-n.com</homepage>
</user>
</users>
EOT;
$sxe = new SimpleXMLElement($xml);
// 这将删除第一个 user 节点
unset($sxe->user[0]);
// 这将删除所有 user 节点
unset($sxe->user);
echo
$sxe->asXML();
?>
2
Patanjali
3 年前
为了比较两个 SimpleXML 元素,请根据 rmirabelle 的评论,对 dom_import_simplexml 函数返回的对象进行比较,例如:

<?php
if(dom_import_simplexml($simplexml_element_1)===dom_import_simplexml($simplexml_element_2)){
...
}
?>

你必须确保两者在转换为 DOM 对象之前都是 SimpleXML 元素。
1
guilhermeasn at yahoo dot com dot br
4 年前
包含将数组或对象转换为 XML 的方法的类

class MakeXML {

public static function array_obj_to_xml($data, \SimpleXMLElement &$xmlObj) {
foreach((array) $data as $key => $value) {
if(is_numeric($key)) {
$key = "n" . $key;
}
if(is_array($value) or is_object($value)) {
$subnode = $xmlObj->addChild($key);
self::array_obj_to_xml($value, $subnode);
} else {
$xmlObj->addChild($key, htmlspecialchars($value));
}
}
}

}

示例

$object = new \stdClass();
$object->example = "Try this class";

$objxml = new \SimpleXMLElement('<API/>');
MakeXML::array_obj_to_xml($objxml, $objxml);
echo $objxml->asXML();
0
Budu
6 年前
public function crearXml(){
$pruebaXml = <<<XML
<?xml version="1.0" encoding="UTF-8" ?>
<Root></Root>
XML;
$example = new SimpleXMLElement($pruebaXml); // 创建一个新的 SimpleXMLElement 对象
$example->addAttribute('id', '1');// 向 XML 节点添加子元素

while( $nodo = $this->iteraciones->iterate()){
$nodos = $example->addChild('Nodo');
$nodos->addAttribute('id',$nodo->getId());
$acierto = $nodos->addChild('nuevoHijo', $nodo->getX());
}
$miFichero = $example->asXML();// 返回基于 SimpleXML 元素的正确 XML 字符串
$miArchivo = fopen("xml/example.xml", "w+");// 打开文件或 URL
fwrite($miArchivo, $miFichero);// 写入文件
}
1
xxxargonxxx at gmail dot com
7 年前
如何查看、编辑和删除元素。
用 CRUD 样式来说,没有读取、编辑和删除节点的方法。但这是可能的。

2. 子节点的工作原理(理解)
<?php
echo "练习 2 \n";

$rootNode = new SimpleXMLElement('<xml_root>complex node</xml_root>'); // 创建根节点
$childNode1 = $rootNode->addChild('type_one','node 1'); // 创建名为 'type_one' 的子节点 1
$childNode2 = new SimpleXMLElement('<type_one>node 2</type_one>'); // 创建名为 'type_one' 的子节点 2
$childNode3 = new SimpleXMLElement('<type_two>node 3</type_two>'); // 创建名为 'type_two' 的子节点 3(不同)
// 现在 $rootNode 只有一个子节点,因为其他子节点是单独创建的
// 将子节点粘贴到根节点
echo $childNode1;

$rootNode->{'type_one'} = $childNode2; // 注意属性名称是 'type_one'
$rootNode->{'type_two'} = $childNode3; // 注意属性名称是 'type_two'
var_dump($rootNode);
/*
object(SimpleXMLElement)#68 (2) {
["type_one"]=>
string(6) "node 2"
["type_two"]=>
string(6) "node 3"
}
*/
// 我们看到 "node 1" 消失了,这是因为将一个节点分配给另一个节点的某个属性不是魔术。
// 为了清楚起见,真正的调用看起来像这样:
$rootNode->{'type_one'}[0] = (string) $childNode2;
$rootNode->{'type_two'}[0] = (string) $childNode3;
// 解释:
// A: (string)
// 这意味着你不能分配节点本身,只能分配它的字符串表示形式,因为分配的节点无论如何都会被强制转换为字符串。
// 这也意味着分配的节点的标签名称无关紧要 - 它的名称将是你指定在 {} 大括号中的名称。
// B: [0]
// 数组访问运算符 ([0]) 意味着每个标签名称(type_one 和 type_two)都有自己的带有整数索引的集合。
// 如果你想添加另一个具有相同名称的标签,你应该递增索引:
$rootNode->{'type_one'}[1] = $childNode2;
var_dump($rootNode);
/*
object(SimpleXMLElement)#68 (2) {
["type_one"]=>
array(2) {
[0]=>
string(6) "node 2"
[1]=>
string(6) "node 2"
}
["type_two"]=>
string(6) "node 3"
}
*/

// 注意 1. $childNode1 的值已更改为 "node 1" - 这是因为从 addChild() 方法返回的子节点
// 与父节点引用。如果在一侧更改其内容 - 它也会在另一侧更改:
$childNode1->{0} = 'renewed node 1';
// 但它不会发生在 $childNode2 上 - 它是一个单一的节点,没有与父节点引用:
$childNode2->{0} = 'renewed node 2';
var_dump($rootNode);
/*
object(SimpleXMLElement)#68 (2) {
["type_one"]=>
array(2) {
[0]=>
string(14) "renewed node 1"
[1]=>
string(6) "node 2"
}
["type_two"]=>
string(6) "node 3"
}
*/

// 注意 2. 当你添加子节点时,父节点的字符串内容仍然存在,var_dump 不会显示它,
// 但你可以通过回显 XML 来看到:
echo "--1--\n".$rootNode->asXML();
/*
<xml_root>complex node <--------- 这里!
<type_one>renewed node 1</type_one>
<type_two>node 3</type_two>
<type_one>node 2</type_one>
</xml_root>
*/
// 看到 'complex node' 了吗?坏消息是,你不能再更改字符串内容了,如果我们尝试调用 `$rootNode->{0} = 'something'` -
// 它会覆盖所有内容 - 既包括字符串,也包括子节点!我不知道在这种情况下如何只写入字符串内容。
// 但你仍然可以读取字符串内容,并像上面描述的那样删除整个节点。

// 因此,以下语句给出了相同的结果,除了 $result 变量的值:
$someNode = new SimpleXMLElement('<div>text</div>');
$result = $rootNode->addChild('div','text'); // $result 是 SimpleXMLElement
$result = $rootNode->addChild($someNode->getName(),$someNode); // $result 是 SimpleXMLElement
$result = $rootNode->{'div'}[] = 'text*'; // $result 是字符串 'text*'
$result = $rootNode->{$someNode->getName()}[] = $someNode; // $result 是字符串 'text'
?>
0
xxxargonxxx at gmail dot com
7 年前
请查看前两部分,以更好地了解这些技巧的工作原理。此处显示的示例指的是第二部分。(抱歉,长度限制)

3. 技巧
<?php
// 真正的利润在于属性和数组访问的组合,以及 unset($someNode->{0}) 技巧 -
// 它允许你删除任何你想要的节点:
unset($rootNode->{'div'}[2]); // 删除带 * 标记的节点 (text*)

// 另一个技巧是使用子节点对象删除子节点
$newChildNode = $rootNode->addChild('div','text**'); // 创建
unset($newChildNode->{0}); // 删除,节点也从父对象中删除!

echo "--2--\n".$rootNode->asXML();
/*
<xml_root>complex node
<type_one>renewed node 1</type_one>
<type_two>node 3</type_two>
<type_one>node 2</type_one>
<div>text</div>
<div>text</div>
<div>text</div>
</xml_root>
*/
?>
0
Yukull
11 年前
xml 到对象转换函数
<?php
/**
@param:
$xml: SimpleXMLElement
$force: 设置为 true 以始终创建 'text'、'attribute' 和 'children',即使它们为空
@return
具有以下属性的对象:
(string) name: XML 标签名称
(string) text: 属性名称的文本内容
(array) attributes: 键为属性键、值为属性值的数组
(array) children: 使用 xml2obj() 在每个子节点上创建的对象数组
**/
function xml2obj($xml,$force = false){

$obj = new StdClass();

$obj->name = $xml->getName();

$text = trim((string)$xml);
$attributes = array();
$children = array();

foreach(
$xml->attributes() as $k => $v){
$attributes[$k] = (string)$v;
}

foreach(
$xml->children() as $k => $v){
$children[] = xml2obj($v,$force);
}


if(
$force or $text !== '')
$obj->text = $text;

if(
$force or count($attributes) > 0)
$obj->attributes = $attributes;

if(
$force or count($children) > 0)
$obj->children = $children;


return
$obj;
}
?>
0
ms dot n at 163 dot com
13 年前
为 SimpleXMLElement 类添加一个新函数,以便输出 HTML 代码。

<?php
class CeiXML extends SimpleXMLElement{
public function
asHTML(){
$ele=dom_import_simplexml($this);
$dom = new DOMDocument('1.0', 'utf-8');
$element=$dom->importNode($ele,true);
$dom->appendChild($element);
return
$dom->saveHTML();
}
}
?>
-1
kweij at lsg dot nl
14 年前
我正在使用 SimpleXML,当然,是为了它的简洁性,但我确实想操作 xml 并将一个 SimpleXMLElement 与任何其他元素结合起来,因此我编写了这个函数来添加一个 SimpleXMLElement 子节点。

<?php
function SimpleXMLElement_append($key, $value) {
// 检查类
if ((get_class($key) == 'SimpleXMLElement') && (get_class($value) == 'SimpleXMLElement')) {
// 检查 value 是否为字符串值/数据
if (trim((string) $value) == '') {
// 添加元素和属性
$element = $key->addChild($value->getName());
foreach (
$value->attributes() as $attKey => $attValue) {
$element->addAttribute($attKey, $attValue);
}
// 添加子节点
foreach ($value->children() as $child) {
SimpleXMLElement_append($element, $child);
}
} else {
// 设置此项目的 value
$element = $key->addChild($value->getName(), trim((string) $value));
}
} else {
// 抛出错误
throw new Exception('输入参数类型错误,预期为 SimpleXMLElement');
}
}
?>

我建议 SimpleXMLElement 扩展其 addChild() 函数,使其具有上述功能。
-1
kurtbr at gmail dot com
7 年前
这是一个将 PHP 数组转换为 XML 的辅助类
你可以通过以下方式调用它:

<?php
$xml
= new Xml();
$xml-> generateXmlFromArray($array, 'entities', 'entity');
?>

<?php
class Xml
{
public function
getXmlFromArray($value, \SimpleXMLElement &$xmlElement, $entity, $starting = null)
{

$handleValue = function($value){
if(
is_string($value)){
$value = htmlspecialchars($value);
}
return
$value;
};
$addChild = function($name, $value, &$subNode = null)use(&$xmlElement, $handleValue, $entity){
if(
is_array($value)){
if(!
$subNode instanceof \SimpleXMLElement){
$currentKey = key($value);
$initialValue = null;
if(
is_numeric($currentKey)){
if(!
is_array($value[$currentKey])){
$initialValue = $value[$currentKey];
unset(
$value[$currentKey]);
}
}
$subNode = $xmlElement->addChild($name, $initialValue);
}
$this->getXmlFromArray($handleValue($value), $subNode, $name);
} else {
$xmlElement->addChild($name, $handleValue($value));
}
};

if(
is_array($value))
{
if(
is_numeric(key($value))){
$setSubNodePrimitiveValue = function($value)use(&$xmlElement, $entity, $handleValue){
$value = $handleValue($value);
$children = $xmlElement->children();
$children[] = $value;
};
foreach (
$value as $item)
{
if(!
is_array($item)){
$setSubNodePrimitiveValue($item);
} else {
if(
$starting === true){
$addChild($entity, $item);
} else {
$addChild($entity, $item, $xmlElement);
}
}
}
} else {
foreach (
$value as $subEntity => $subEntityItem)
{
$addChild($subEntity, $subEntityItem);
}
}
} else {
$xmlElement->addChild($entity, $handleValue($value));
}
}

/**
* @param array $array
* @param string $openingTag
* @param string $entity
* @param string $nameSpace
* @param bool $isPrefixed
* @return \SimpleXMLElement
*/
public function generateXmlFromArray(array $array, string $openingTag, string $entity, $nameSpace = '', $isPrefixed = false)
{
$xmlString = '<'.$openingTag.'></'.$openingTag.'>';
$xml = new \SimpleXMLElement($xmlString, LIBXML_NOERROR, false, $nameSpace, $isPrefixed);
$this->getXmlFromArray($array, $xml, $entity, true);
return
$xml;
}

/**
* @param string $xml
* @return bool
*/
public function validateXml(string $xml)
{
$dom = new \DOMDocument();
$dom->loadXML($xml);
return
$dom->validate();
}

public function
loadXmlPathAsArray(string $xmlPath)
{
$xml = simplexml_load_file($xmlPath);
$array = json_decode(json_encode($xml), TRUE);
return (array)
$array;
}

/**
* @param string $xmlString
* @return array
*/
public function loadXmlStringAsArray(string $xmlString)
{
$array = (array) @simplexml_load_string($xmlString);
if(!
$array){
$array = (array) @json_decode($xmlString, true);
} else{
$array = (array)@json_decode(json_encode($array), true);
}
return
$array;
}

/**
* @param string $xmlString
* @return \SimpleXMLElement
*/
public function loadXmlString(string $xmlString)
{
return @
simplexml_load_string($xmlString);
}
}
?>
-4
Pavel Musil pavel dot musil at gmail dot com
13 年前
将 XML 对象附加到 SimpleXMLElement 节点的简单递归函数

<?php
// root: 父元素 - SimpleXMLElement 实例
// append: 来自 simplexml_load_string 的 XML 对象

function xml_join($root, $append) {
if (
$append) {
if (
strlen(trim((string) $append))==0) {
$xml = $root->addChild($append->getName());
foreach(
$append->children() as $child) {
xml_join($xml, $child);
}
} else {
$xml = $root->addChild($append->getName(), (string) $append);
}
foreach(
$append->attributes() as $n => $v) {
$xml->addAttribute($n, $v);
}
}
}

$xml_append = simplexml_load_string('<data><items><item id="1">value</item></items></data>');
$xml_root = new SimpleXMLElement('<result></result>');

$cxml = $xml_root->addChild('clone');
xml_join($cxml, $xml_append->items->item[0]);

print
$xml_root->asXML();
?>

结果
<?xml version="1.0"?>
<result>
<clone>
<item id="1">
value
</item>
</clone>
</result>
-8
dans at dansheps dot com
13 年前
我创建了一个小函数来解析简单的 XML,将其转换为更易于迭代的结构(至少我认为是这样),而不是简单的 XML 节点结构。

<?php
function parseSimpleXML($xmldata)
{
$childNames = array();
$children = array();

if(
$xmldata->count() !== 0 )
{
foreach(
$xmldata->children() AS $child )
{
$name = $child->getName();

if( !isset(
$childNames[$name]) )
{
$childNames[$name] = 0;
}

$childNames[$name]++;
$children[$name][] = $this->parseSimpleXML($child);
}
}

$returndata = new XMLNode();
if(
$xmldata->attributes()->count() > 0 )
{
$returndata->{'@attributes'} = new XMLAttribute();
foreach(
$xmldata->attributes() AS $name => $attrib )
{
$returndata->{'@attributes'}->{$name} = (string)$attrib;
}
}

if(
count($childNames) > 0 )
{
foreach(
$childNames AS $name => $count )
{
if(
$count === 1 )
{
$returndata->{$name} = $children[$name][0];
}
else
{
$returndata->{$name} = new XMLMultiNode();
$counter = 0;
foreach(
$children[$name] AS $data )
{
$returndata->{$name}->{$counter} = $data;
$counter++;
}
}
}
}
else
{
if( (string)
$xmldata !== '' )
{
$returndata->{'@innerXML'} = (string)$xmldata;
}
}
return
$returndata;
}
?>
-3
xxxargonxxx at gmail dot com
7 年前
如何查看、编辑和删除元素。
用 CRUD 样式来说,没有读取、编辑和删除节点的方法。但这是可能的。

1. 如何处理单个节点及其值(基础)
<?php
echo "Exercise 1 \n";
// Create
$someNode = new SimpleXMLElement('<xml_root>simple node</xml_root>');
// Read
echo $someNode->{0} ."\n"; // Echoes "simple node"
echo $someNode ."\n"; // Echoes "simple node", might be used for read case too
// Edit
$someNode->{0} = 'new value';
echo
$someNode->{0} ."\n"; // Echoes "new value", value is changed!
// Remove
unset($someNode->{0});

// Don't touch this node anymore otherwise it will throw a warning:
// "Warning: SimpleXMLElement::asXML(): Node no longer exists in <...> on line <...>"
// echo $someNode ."\n"; // Throws the warning

// Recap: property access to zero property ($someNode->{0}) is the way to read and edit string content of the node AND
// to remove the node itself
?>
To Top