PHP Conference Japan 2024

SimpleXML

新增註解

使用者貢獻註解 15 則註解

288
soloman at textgrid dot com
13 年前
三行 xml2array

<?php

$xml
= simplexml_load_string($xmlstring);
$json = json_encode($xml);
$array = json_decode($json,TRUE);

?>

瞧!
6
QLeap
16 年前
將 SimpleXMLElement 值儲存在 $_SESSION 中無效。將結果儲存為物件或物件的個別元素,將導致可怕的「Warning: session_start() [function.session-start]: Node no longer exists」錯誤。

例如,這無效

$xml = new SimpleXMLElement($page);
$country = $xml->Response->Placemark->AddressDetails->Country->CountryNameCode;
$_SESSION['country'] = $country;

這樣會有效

$_SESSION['country'] = (string) $country;
11
xaviered at gmail dot com
12 年前
這是一個遞迴函式,會將給定的 SimpleXMLElement 物件轉換為陣列,同時保留命名空間和屬性。

<?php
function xmlObjToArr($obj) {
$namespace = $obj->getDocNamespaces(true);
$namespace[NULL] = NULL;

$children = array();
$attributes = array();
$name = strtolower((string)$obj->getName());

$text = trim((string)$obj);
if(
strlen($text) <= 0 ) {
$text = NULL;
}

// get info for all namespaces
if(is_object($obj)) {
foreach(
$namespace as $ns=>$nsUrl ) {
// atributes
$objAttributes = $obj->attributes($ns, true);
foreach(
$objAttributes as $attributeName => $attributeValue ) {
$attribName = strtolower(trim((string)$attributeName));
$attribVal = trim((string)$attributeValue);
if (!empty(
$ns)) {
$attribName = $ns . ':' . $attribName;
}
$attributes[$attribName] = $attribVal;
}

// children
$objChildren = $obj->children($ns, true);
foreach(
$objChildren as $childName=>$child ) {
$childName = strtolower((string)$childName);
if( !empty(
$ns) ) {
$childName = $ns.':'.$childName;
}
$children[$childName][] = xmlObjToArr($child);
}
}
}

return array(
'name'=>$name,
'text'=>$text,
'attributes'=>$attributes,
'children'=>$children
);
}
?>
4
mahmutta at gmail dot com
14 年前
當使用 simple xml 並從 xml 物件中取得 double 或 float 的 int 值來進行數學運算 (+ * - /) 時,運算會發生一些錯誤,這是因為 simple xml 會將所有內容都回傳為物件。
範例:

<?php

$name
= "somestring";
$size = 11.45;
$xml = '
<xml>
<name>somestring</name>
<size>11.45</size>
</xml>'
;


$xmlget = simplexml_load_string($xml)

echo
$xml->size*2; // 20 這是錯的
// ($xml->size 是一個物件 (int)11 和 (45) )

// 這是正確的
echo $size*2; // 22.90
echo (float)$size*2; // 22.90
?>
4
kristof at viewranger dot com
14 年前
如果你嘗試用這個載入 XML 檔案,但由於某些原因沒有載入 CDATA 部分,那是因為你應該這樣做

$xml = simplexml_load_file($this->filename, 'SimpleXMLElement', LIBXML_NOCDATA);

這會將返回的物件中的 CDATA 轉換為字串。
3
oscargodson at gmail dot com
15 年前
為了補充其他人的說法,你不能直接將 $_GET 或 $_POST 的值放入變數,然後使用 SimpleXML 放入屬性。你必須先將它轉換為整數。

這不會起作用

<?php
$page_id
= $_GET['id'];
echo
$xml->page[$page_id]
?>

你會得到類似這樣的東西
Notice: Trying to get property of non-object in /Applications/MAMP/htdocs/mysite/index.php on line 10

然而,這個會起作用,而且比使用 (string) 或其他方法簡單得多。
<?php
$page_id
= intval($_GET['id']);
echo
$xml->page[$page_id]
?>
5
whyme
11 年前
簡單意味著簡單。如果你知道結構,而且只想取得標籤的值

<?php
$xml
= simplexml_load_file($xmlfile);
print
$xml->City->Street->Address->HouseColor;
?>

警告,數字可能會以字串的形式輸出,像 <HouseColor></HouseColor> 這樣的空元素會以 array(0) 的形式輸出
5
aalaap at gmail dot com
16 年前
這裡有兩個快速且簡陋的函式,使用 SimpleXML 來偵測 feed xml 是 RSS 還是 ATOM

<?php
function is_rss($feedxml) {
@
$feed = new SimpleXMLElement($feedxml);

if (
$feed->channel->item) {
return
true;
} else {
return
false;
}
}

function
is_atom($feedxml) {
@
$feed = new SimpleXMLElement($feedxml);

if (
$feed->entry) {
return
true;
} else {
return
false;
}
}
?>

這些函式會接收完整的文字 feed(例如,透過 cURL 擷取),並根據結果返回 true 或 false。
4
dkrnl at yandex dot ru
11 年前
用於簡單 SAX 讀取巨大 XML 的 XMLReader 類別包裝器
https://github.com/dkrnl/SimpleXMLReader

使用範例:http://github.com/dkrnl/SimpleXMLReader/blob/master/examples/example1.php

<?php

/**
* 簡易 XML 讀取器
*
* @license Public Domain (公有領域)
* @author Dmitry Pyatkov(aka dkrnl) <dkrnl@yandex.ru>
* @url http://github.com/dkrnl/SimpleXMLReader
*/
class SimpleXMLReader extends XMLReader
{

/**
* 回呼函式
*
* @var array
*/
protected $callback = array();

/**
* 新增節點回呼函式
*
* @param string $name
* @param callback $callback
* @param integer $nodeType
* @return SimpleXMLReader
*/
public function registerCallback($name, $callback, $nodeType = XMLREADER::ELEMENT)
{
if (isset(
$this->callback[$nodeType][$name])) {
throw new
Exception("已存在回呼函式 $name($nodeType).");
}
if (!
is_callable($callback)) {
throw new
Exception("已存在解析器回呼函式 $name($nodeType).");
}
$this->callback[$nodeType][$name] = $callback;
return
$this;
}

/**
* 移除節點回呼函式
*
* @param string $name
* @param integer $nodeType
* @return SimpleXMLReader
*/
public function unRegisterCallback($name, $nodeType = XMLREADER::ELEMENT)
{
if (!isset(
$this->callback[$nodeType][$name])) {
throw new
Exception("未知的解析器回呼函式 $name($nodeType).");
}
unset(
$this->callback[$nodeType][$name]);
return
$this;
}

/**
* 執行解析器
*
* @return void
*/
public function parse()
{
if (empty(
$this->callback)) {
throw new
Exception("空的解析器回呼函式。");
}
$continue = true;
while (
$continue && $this->read()) {
if (isset(
$this->callback[$this->nodeType][$this->name])) {
$continue = call_user_func($this->callback[$this->nodeType][$this->name], $this);
}
}
}

/**
* 在目前節點上執行 XPath 查詢
*
* @param string $path
* @param string $version
* @param string $encoding
* @return array(SimpleXMLElement)
*/
public function expandXpath($path, $version = "1.0", $encoding = "UTF-8")
{
return
$this->expandSimpleXml($version, $encoding)->xpath($path);
}

/**
* 將目前節點展開為字串
*
* @param string $version
* @param string $encoding
* @return SimpleXMLElement
*/
public function expandString($version = "1.0", $encoding = "UTF-8")
{
return
$this->expandSimpleXml($version, $encoding)->asXML();
}

/**
* 將目前節點展開為 SimpleXMLElement
*
* @param string $version
* @param string $encoding
* @param string $className
* @return SimpleXMLElement
*/
public function expandSimpleXml($version = "1.0", $encoding = "UTF-8", $className = null)
{
$element = $this->expand();
$document = new DomDocument($version, $encoding);
$node = $document->importNode($element, true);
$document->appendChild($node);
return
simplexml_import_dom($node, $className);
}

/**
* 將目前節點展開為 DomDocument
*
* @param string $version
* @param string $encoding
* @return DomDocument
*/
public function expandDomDocument($version = "1.0", $encoding = "UTF-8")
{
$element = $this->expand();
$document = new DomDocument($version, $encoding);
$node = $document->importNode($element, true);
$document->appendChild($node);
return
$document;
}

}
?>
5
streaver91 at gmail dot com
13 年前
XML 和 PHP 陣列之間最大的差異在於,在 XML 檔案中,即使元素是同層級的,它們的名稱也可以相同,例如 "<pa><ch /><ch /><ch /></pa>",而在 PHP 陣列中,索引鍵必須不同。

我認為 svdmeer 開發的陣列結構可以適用於 XML,而且非常適合。

這是一個從 XML 檔案轉換而來的陣列範例
array(
"@tag"=>"name",
"@attr"=>array(
"id"=>"1","class"=>"2")
"@text"=>"一些文字",
)

或者,如果它有子元素,則可以是

array(
"@tag"=>"name",
"@attr"=>array(
"id"=>"1","class"=>"2")
"@items"=>array(
0=>array(
"@tag"=>"name","@text"=>"一些文字"
)
)

此外,我寫了一個函式,可以將該陣列變回 XML。

<?php
function array2XML($arr,$root) {
$xml = new SimpleXMLElement("<?xml version=\"1.0\" encoding=\"utf-8\" ?><{$root}></{$root}>");
$f = create_function('$f,$c,$a','
foreach($a as $v) {
if(isset($v["@text"])) {
$ch = $c->addChild($v["@tag"],$v["@text"]);
} else {
$ch = $c->addChild($v["@tag"]);
if(isset($v["@items"])) {
$f($f,$ch,$v["@items"]);
}
}
if(isset($v["@attr"])) {
foreach($v["@attr"] as $attr => $val) {
$ch->addAttribute($attr,$val);
}
}
}'
);
$f($f,$xml,$arr);
return
$xml->asXML();
}
?>
4
philipp at strazny dot com
14 年前
這裡有一個快速的方法,可以將 SimpleXML 中的節點值傾印到一個陣列中,並使用每個節點值的路徑作為索引鍵。這些路徑與例如 DOMXPath 相容。當我需要從外部更新值時(即在不了解底層 XML 的程式碼中),我會使用這個方法。然後我使用 DOMXPath 找到包含原始值的節點並更新它。

<?php
function XMLToArrayFlat($xml, &$return, $path='', $root=false)
{
$children = array();
if (
$xml instanceof SimpleXMLElement) {
$children = $xml->children();
if (
$root){ // 我們在根節點
$path .= '/'.$xml->getName();
}
}
if (
count($children) == 0 ){
$return[$path] = (string)$xml;
return;
}
$seen=array();
foreach (
$children as $child => $value) {
$childname = ($child instanceof SimpleXMLElement)?$child->getName():$child;
if ( !isset(
$seen[$childname])){
$seen[$childname]=0;
}
$seen[$childname]++;
XMLToArrayFlat($value, $return, $path.'/'.$child.'['.$seen[$childname].']');
}
}
?>

像這樣使用

<?php
$xml
= simplexml_load_string(...一些 XML 字串...);
$xmlarray = array(); // 這會儲存攤平後的資料
XMLToArrayFlat($xml, $xmlarray, '', true);
?>

您也可以將多個檔案放入一個陣列中

<?php
foreach($files as $file){
$xml = simplexml_load_file($file);
XMLToArrayFlat($xml, $xmlarray, $file.':', true);
}
?>
因此,每個鍵都會加上對應的檔案名稱/路徑作為前綴。
2
phil at dier dot us
13 年前
這裡有一個我寫的函式,用於將關聯陣列轉換為 XML。也適用於多維陣列。

<?php
function assocArrayToXML($root_element_name,$ar)
{
$xml = new SimpleXMLElement("<?xml version=\"1.0\"?><{$root_element_name}></{$root_element_name}>");
$f = create_function('$f,$c,$a','
foreach($a as $k=>$v) {
if(is_array($v)) {
$ch=$c->addChild($k);
$f($f,$ch,$v);
} else {
$c->addChild($k,$v);
}
}'
);
$f($f,$xml,$ar);
return
$xml->asXML();
}
?>
2
emmanuel
14 年前
在 PHP 中使用 XML 的動態 SQL

test.xml
<?xml version="1.0" encoding="UTF-8"?>
<sql>
<statement>
SELECT * FROM USERS
<call criteria="byId">WHERE id = %d</call>
<call criteria="byUsername">WHERE username = "%s"</call>;
</statement>
</sql>

index.php
<?php
function callMe($param) {
$search = array('byUsername' => 'dynsql');

if (isset(
$search[$param[1]])) {
return
sprintf($param[2], $search[$param[1]]);
}

return
"";
}

$xml = simplexml_load_file("test.xml");
$string = $xml->statement->asXML();
$string = preg_replace_callback('/<call criteria="(\w+)">(.*?)<\/call>/', 'callMe', $string);
$node = simplexml_load_string($string);
echo
$node;
?>

顯然,這個範例可以(在您自己的程式碼中)改進。
2
mail at kleineedv dot de
15 年前
我有一個問題,就是 simplexml 無法從 XML 檔案中讀取節點。它總是回傳一個 SimpleXML 物件,而不是節點內的文字。

範例
<?xml version="1.0" encoding="UTF-8"?>
<Test>
<Id>123</Id>
</Test>

將這個 XML 讀入一個名為 $xml 的變數中,然後執行以下操作
<?php
$myId
= $xml->Id;
?>
$myId 沒有回傳 123,而是得到了一個 SimpleXMLElement 物件。

解決方案很簡單,當您知道時。使用明確的字串轉換。
<?php
$myId
= (string)$xml->Id;
?>
0
oleg at mastak dot fi
8 年前
兩行程式碼的 xml2array

<?php

$xml
= simplexml_load_string($xmlstring);
$array = (array) $xml;

?>
To Top