PHP 日本研討會 2024

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

目錄

新增註解

使用者貢獻的註解 27 條註解

rmirabelle
14 年前
為了進一步說明之前的評論並強調重點

SimpleXMLElement 難以使用的原因在於,它給人感覺和行為都像物件,但實際上是一個系統資源 (具體來說是一個 libxml 資源)。

這就是為什麼您不能將 SimpleXMLElement 儲存到 $_SESSION,或者在沒有先將節點值強制轉換為某種類型的物件的情況下執行直接比較運算的原因。 $_SESSION 期望儲存「一個物件」,而比較運算子期望比較 2 個「物件」,而 SimpleXMLElement 並非物件。

當您 echo 或 print 節點的值時,PHP 會為您將值 (一個資源) 轉換為字串物件。這絕對可以節省時間,但也可能會讓您誤以為您的 SimpleXMLElement 是一個物件。

希望這有助於釐清
juanfhj at gmail dot spam dot me dot not dot com
13 年前
若要將基礎元素作為字串存取,必須執行轉換 $x = (string)$my_xml_element。
匿名
13 年前
警告任何嘗試使用包含連字號的金鑰名稱來解析 XML 的人,例如:)
<subscribe>
<callback-url>example url</callback-url>
</subscribe>

為了存取 callback-url,您需要執行如下操作
<?php
$xml
= simplexml_load_string($input);
$callback = $xml->{"callback-url"};
?>
如果您嘗試在沒有大括號和引號的情況下執行此操作,您會發現您收到的是 0 而不是您想要的結果。
saganmarketing.com
12 年前
通過 SimpleXML 解析無效的 XML 字串通常會導致腳本完全崩潰,因此最好在解析之前確保 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 . ' 在第 ' . $error->line . ' 行。無效 XML:' . htmlentities($badxml);
return $message;
}
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)
];
}
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);
?>

會擲回例外。一個 Q&D 是將任意的根節點結構附加到輸入的兩端

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

這樣做也可以解決上述根節點屬性存取問題。(如果您的 XML 字串包含宣告,則可能無法正常運作。)
Patanjali
4 年前
接續 rmirabelle 的評論,若要比較兩個 SimpleXML 元素,請依照以下方式比較 dom_import_simplexml 函式所回傳的物件

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

您必須先確保兩者都是 SimpleXML 元素,然後再轉換為 DOM 物件。
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'; // 有效!
?>
heaver
12 年前
不含 '@attributes' 的 XML 轉 JSON
<?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);
}
?>
brett at brettbrewer dot com
15 年前
對我來說,弄清楚如何存取 SimpleXmlElement 物件的屬性有點棘手。特別是,我花了一段時間才發現我需要將 SimpleXmlElement 屬性轉換為 "string" 類型,才能列印它們或對它們進行比較。例如,假設您已經在 $xmlstr 中有一個 xml 字串...

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

if ((string)
$sxml->property== "somevalue") {
echo (string)
$sxml->property;
}
?>
SimpleXmlElement 物件的屬性本身就是物件,因此您需要在它們前面加上 "(string)",這會將它們的值轉換為字串而不是物件。我假設如果您要進行數值比較,您會想要轉換為 (int) 或其他數值類型。
ivandosreisandrade at gmail dot com
15 年前
您好,

這是我的貢獻,獻給那些正在努力理解 SimpleXMLElement 如何運作的人。

在花了一些時間試圖弄清楚它是如何運作的之後,我想出了這個小範例

<?php
$xmlstr
= "<?xml version='1.0' ?>\n".
// 可選擇為呈現結果指定一個 xml 樣式表。只需取消註解以下行並更改樣式表名稱。
/* "<?xml-stylesheet type='text/xsl' href='xml_style.xsl' ?>\n". */
"<book></book>";

// 使用一個空的 <book> 元素建立 SimpleXMLElement 物件
$xml = new SimpleXMLElement($xmlstr);

// 新增一些子節點
$xml->addChild("title", "我的書名");
$xml->addChild("abstract", "我的書是關於學習如何使用 SimpleXMLElement");

// 新增更多子節點
$chapter1 = $xml->addChild("chapter_1");
// 為子節點 chapter_1 新增一個屬性
$chapter1->addAttribute("chapter_title", "我的書的導論");

$chapter2 = $xml->addChild("chapter_2");
$chapter2->addAttribute("chapter_title", "我的書的發展");

$chapter3 = $xml->addChild("chapter_3");
$chapter3->addAttribute("chapter_title", "我的書的另一個章節");

$conclusion = $xml->addChild("conclusion", "我的書的結尾");

// 插入標頭以告知瀏覽器如何讀取文件
header("Content-type: text/xml");
// 將 SimpleXMLElement 列印為格式良好的 XML 字串
echo $xml->asXML();
?>

使用此腳本,您只需複製貼上並嘗試了解它的運作方式。
我希望它能幫助到某些人:)
francs at seznam dot cz
14 年前
當您嘗試將某些屬性轉換為布林值時,請注意。

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

如果屬性是 array([0] => 0),則返回 TRUE;

請改用 (boolean)(int)。
triplepoint at gmail dot com
14 年前
偶爾將 XML 處理指令新增至 SimpleXMLElement(將其視為完整文件)會很有用。
<?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);
}
}
?>

例如,如果您的 simpleXMLElement_Plus 物件是由 xml 片段組成的
<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();
?>
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()。它能清楚地顯示真實的連結索引。
demian dot katz at villanova dot edu
12 年前
這是一個早期的函數,用於將一個 SimpleXMLElement 附加到另一個 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);
}
}
}
joshduck at gmail dot com
14 年前
如果您計劃在加法、乘法等運算中使用元素,您應該將它們轉換為浮點數(甚至是字串)。如果您不這樣做,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)
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);
// 這將移除第一個使用者節點
unset($sxe->user[0]);
// 這將移除所有使用者節點
unset($sxe->user);
echo
$sxe->asXML();
?>
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();
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);// 寫入檔案
}
xxxargonxxx at gmail dot com
7 年前
如何檢視、編輯和移除元素。
以 CRUD 風格來說,沒有方法可以讀取、編輯和移除節點。但這是可能的。

2. 子節點如何運作(理解)
<?php
echo "練習 2 \n";

$rootNode = new SimpleXMLElement('<xml_root>複雜節點</xml_root>'); // 建立根節點
$childNode1 = $rootNode->addChild('type_one','節點 1'); // 建立名為 'type_one' 的子節點 1
$childNode2 = new SimpleXMLElement('<type_one>節點 2</type_one>'); // 建立名為 'type_one' 的子節點 2
$childNode3 = new SimpleXMLElement('<type_two>節點 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) "節點 2"
["type_two"]=>
string(6) "節點 3"
}
*/
// 我們看到 "節點 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) "節點 2"
[1]=>
string(6) "節點 2"
}
["type_two"]=>
string(6) "節點 3"
}
*/

// 注意 1. $childNode1 的值已變更為 "節點 1" - 這是因為從 addChild() 方法傳回的子節點會參考父節點。如果您在一側變更其內容 - 它也會在另一側變更:
$childNode1->{0} = '更新後的節點 1';
// 但這不會發生在 $childNode2 上 - 它是單獨的,且沒有參考父節點:
$childNode2->{0} = '更新後的節點 2';
var_dump($rootNode);
/*
object(SimpleXMLElement)#68 (2) {
["type_one"]=>
array(2) {
[0]=>
string(14) "更新後的節點 1"
[1]=>
string(6) "節點 2"
}
["type_two"]=>
string(6) "節點 3"
}
*/

// 注意 2. 當您新增子節點時,父節點的字串內容仍然存在,var_dump 不會顯示它,
// 但您可以透過輸出 XML 來看到:
echo "--1--\n".$rootNode->asXML();
/*
<xml_root>複雜節點 <--------- 在這裡!
<type_one>更新後的節點 1</type_one>
<type_two>節點 3</type_two>
<type_one>節點 2</type_one>
</xml_root>
*/
// 看到 '複雜節點' 嗎?壞消息是您無法再變更字串內容,如果我們嘗試呼叫 `$rootNode->{0} = 'something'` -
// 它會覆寫所有內容 - 包括字串和子節點!我不知道如何僅在這種情況下寫入字串內容。
// 但是您仍然可以讀取字串內容並如上所述移除整個節點。

// 因此,以下陳述式會產生相同的結果,除了 $result 變數的值:
$someNode = new SimpleXMLElement('<div>文字</div>');
$result = $rootNode->addChild('div','文字'); // $result 是 SimpleXMLElement
$result = $rootNode->addChild($someNode->getName(),$someNode); // $result 是 SimpleXMLElement
$result = $rootNode->{'div'}[] = '文字*'; // $result 是字串 '文字*'
$result = $rootNode->{$someNode->getName()}[] = $someNode; // $result 是字串 '文字'
?>
xxxargonxxx at gmail dot com
7 年前
請參閱前兩個部分,以更好地了解這些技巧的工作原理。此處顯示的範例參考第二部分。(抱歉,長度限制)

3. 技巧
<?php
// 真正的優勢在於屬性和陣列存取的組合,以及 unset($someNode->{0}) 技巧 -
// 它允許您移除您想要的任何節點:
unset($rootNode->{'div'}[2]); // 移除帶有 * 標記的節點 (文字*)

// 另一個技巧是使用子節點物件移除子節點
$newChildNode = $rootNode->addChild('div','文字**'); // 建立
unset($newChildNode->{0}); // 移除,節點也從父物件中移除!

echo "--2--\n".$rootNode->asXML();
/*
<xml_root>複雜節點
<type_one>更新後的節點 1</type_one>
<type_two>節點 3</type_two>
<type_one>節點 2</type_one>
<div>文字</div>
<div>文字</div>
<div>文字</div>
</xml_root>
*/
?>
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;
}
?>
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();
}
}
?>
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')) {
// 檢查值是否為字串值 / 資料
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 {
// 設定此項目的值
$element = $key->addChild($value->getName(), trim((string) $value));
}
} else {
// 拋出錯誤
throw new Exception('輸入參數的類型錯誤,預期為 SimpleXMLElement');
}
}
?>

我建議 SimpleXMLElement 擴展其 addChild() 函式,包含上述功能。
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>
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);
}
}
?>
xxxargonxxx at gmail dot com
7 年前
如何檢視、編輯和移除元素。
以 CRUD 風格來說,沒有方法可以讀取、編輯和移除節點。但這是可能的。

1. 如何處理單一節點及其值 (基礎)
<?php
echo "練習 1 \n";
// 建立
$someNode = new SimpleXMLElement('<xml_root>簡單節點</xml_root>');
// 讀取
echo $someNode->{0} ."\n"; // 輸出 "簡單節點"
echo $someNode ."\n"; // 輸出 "簡單節點",也可用於讀取的情況
// 編輯
$someNode->{0} = '新值';
echo
$someNode->{0} ."\n"; // 輸出 "新值",值已變更!
// 移除
unset($someNode->{0});

// 不要再操作這個節點,否則會拋出警告:
// "Warning: SimpleXMLElement::asXML(): Node no longer exists in <...> on line <...>"
// echo $someNode ."\n"; // 會拋出警告

// 重點:存取零屬性 ($someNode->{0}) 是讀取和編輯節點字串內容的方式,且
// 也可用來移除節點本身
?>
To Top