特定のPHPオブジェクトを取得してXMLとしてシリアル化する最良の方法は何ですか? 私は simple_xml を見ていて、それを使用して XML をオブジェクトに解析しましたが、それが逆にどのように機能するかは明確ではありません。
12 に答える
PEAR の XML_Serializer を使用することに同意しますが、ネストされたプロパティを持つオブジェクト/配列をサポートする単純なものが必要な場合は、これを使用できます。
class XMLSerializer {
// functions adopted from http://www.sean-barton.co.uk/2009/03/turning-an-array-or-object-into-xml-using-php/
public static function generateValidXmlFromObj(stdClass $obj, $node_block='nodes', $node_name='node') {
$arr = get_object_vars($obj);
return self::generateValidXmlFromArray($arr, $node_block, $node_name);
}
public static function generateValidXmlFromArray($array, $node_block='nodes', $node_name='node') {
$xml = '<?xml version="1.0" encoding="UTF-8" ?>';
$xml .= '<' . $node_block . '>';
$xml .= self::generateXmlFromArray($array, $node_name);
$xml .= '</' . $node_block . '>';
return $xml;
}
private static function generateXmlFromArray($array, $node_name) {
$xml = '';
if (is_array($array) || is_object($array)) {
foreach ($array as $key=>$value) {
if (is_numeric($key)) {
$key = $node_name;
}
$xml .= '<' . $key . '>' . self::generateXmlFromArray($value, $node_name) . '</' . $key . '>';
}
} else {
$xml = htmlspecialchars($array, ENT_QUOTES);
}
return $xml;
}
}
PEARのXML_Serializerパッケージを見てください。私はそれをかなり良い結果で使用しました。配列やオブジェクトなどをフィードすると、XMLに変換されます。また、ルートノードの名前を選択するなどのオプションもたくさんあります。
トリックを行う必要があります
元の質問に対する完全な答えではありませんが、これに関する問題を解決する方法は、オブジェクトを次のように宣言することでした。
$root = '<?xml version="1.0" encoding="UTF-8"?><Activities/>';
$object = new simpleXMLElement($root);
とは対照的に:
$object = new stdClass;
値を追加する前に!
それを行うには、dom 関数を使用します: http://www.php.net/manual/en/function.dom-import-simplexml.php
SimpleXML オブジェクトをインポートして保存します。上記のリンクには例が含まれています。:)
手短に:
<?php
$array = array('hello' => 'world', 'good' => 'morning');
$xml = simplexml_load_string("<?xml version='1.0' encoding='utf-8'?><foo />");
foreach ($array as $k=>$v) {
$xml->addChild($k, $v);
}
?>
私のバージョンを見てください
class XMLSerializer {
/**
*
* The most advanced method of serialization.
*
* @param mixed $obj => can be an objectm, an array or string. may contain unlimited number of subobjects and subarrays
* @param string $wrapper => main wrapper for the xml
* @param array (key=>value) $replacements => an array with variable and object name replacements
* @param boolean $add_header => whether to add header to the xml string
* @param array (key=>value) $header_params => array with additional xml tag params
* @param string $node_name => tag name in case of numeric array key
*/
public static function generateValidXmlFromMixiedObj($obj, $wrapper = null, $replacements=array(), $add_header = true, $header_params=array(), $node_name = 'node')
{
$xml = '';
if($add_header)
$xml .= self::generateHeader($header_params);
if($wrapper!=null) $xml .= '<' . $wrapper . '>';
if(is_object($obj))
{
$node_block = strtolower(get_class($obj));
if(isset($replacements[$node_block])) $node_block = $replacements[$node_block];
$xml .= '<' . $node_block . '>';
$vars = get_object_vars($obj);
if(!empty($vars))
{
foreach($vars as $var_id => $var)
{
if(isset($replacements[$var_id])) $var_id = $replacements[$var_id];
$xml .= '<' . $var_id . '>';
$xml .= self::generateValidXmlFromMixiedObj($var, null, $replacements, false, null, $node_name);
$xml .= '</' . $var_id . '>';
}
}
$xml .= '</' . $node_block . '>';
}
else if(is_array($obj))
{
foreach($obj as $var_id => $var)
{
if(!is_object($var))
{
if (is_numeric($var_id))
$var_id = $node_name;
if(isset($replacements[$var_id])) $var_id = $replacements[$var_id];
$xml .= '<' . $var_id . '>';
}
$xml .= self::generateValidXmlFromMixiedObj($var, null, $replacements, false, null, $node_name);
if(!is_object($var))
$xml .= '</' . $var_id . '>';
}
}
else
{
$xml .= htmlspecialchars($obj, ENT_QUOTES);
}
if($wrapper!=null) $xml .= '</' . $wrapper . '>';
return $xml;
}
/**
*
* xml header generator
* @param array $params
*/
public static function generateHeader($params = array())
{
$basic_params = array('version' => '1.0', 'encoding' => 'UTF-8');
if(!empty($params))
$basic_params = array_merge($basic_params,$params);
$header = '<?xml';
foreach($basic_params as $k=>$v)
{
$header .= ' '.$k.'='.$v;
}
$header .= ' ?>';
return $header;
}
}
次のように、再帰的な方法を使用します。
private function ReadProperty($xmlElement, $object) {
foreach ($object as $key => $value) {
if ($value != null) {
if (is_object($value)) {
$element = $this->xml->createElement($key);
$this->ReadProperty($element, $value);
$xmlElement->AppendChild($element);
} elseif (is_array($value)) {
$this->ReadProperty($xmlElement, $value);
} else {
$this->AddAttribute($xmlElement, $key, $value);
}
}
}
}
完全な例: http://www.tyrodeveloper.com/2018/09/convertir-clase-en-xml-con-php.html
@philfreo と、PEAR に依存すべきではないという彼の論拠には同意しますが、彼の解決策はまだ十分ではありません。キーが次の文字のいずれかを含む文字列である可能性がある場合、問題が発生する可能性があります。
- <
- >
- \s (スペース)
- "
- '
XML は文法でこれらの文字を使用するため、これらのいずれかがフォーマットから外れます。したがって、これ以上苦労することなく、非常に起こりうる発生に対する簡単な解決策を次に示します。
function xml_encode( $var, $indent = false, $i = 0 ) {
$version = "1.0";
if ( !$i ) {
$data = '<?xml version="1.0"?>' . ( $indent ? "\r\n" : '' )
. '<root vartype="' . gettype( $var ) . '" xml_encode_version="'. $version . '">' . ( $indent ? "\r\n" : '' );
}
else {
$data = '';
}
foreach ( $var as $k => $v ) {
$data .= ( $indent ? str_repeat( "\t", $i ) : '' ) . '<var vartype="' .gettype( $v ) . '" varname="' . htmlentities( $k ) . '"';
if($v == "") {
$data .= ' />';
}
else {
$data .= '>';
if ( is_array( $v ) ) {
$data .= ( $indent ? "\r\n" : '' ) . xml_encode( $v, $indent, $verbose, ($i + 1) ) . ( $indent ? str_repeat("\t", $i) : '' );
}
else if( is_object( $v ) ) {
$data .= ( $indent ? "\r\n" : '' ) . xml_encode( json_decode( json_encode( $v ), true ), $indent, $verbose, ($i + 1)) . ($indent ? str_repeat("\t", $i) : '');
}
else {
$data .= htmlentities( $v );
}
$data .= '</var>';
}
$data .= ($indent ? "\r\n" : '');
}
if ( !$i ) {
$data .= '</root>';
}
return $data;
}
使用例を次に示します。
// sample object
$tests = Array(
"stringitem" => "stringvalue",
"integeritem" => 1,
"floatitem" => 1.00,
"arrayitems" => Array("arrayvalue1", "arrayvalue2"),
"hashitems" => Array( "hashkey1" => "hashkey1value", "hashkey2" => "hashkey2value" ),
"literalnull" => null,
"literalbool" => json_decode( json_encode( 1 ) )
);
// add an objectified version of itself as a child
$tests['objectitem'] = json_decode( json_encode( $tests ), false);
// convert and output
echo xml_encode( $tests );
/*
// output:
<?xml version="1.0"?>
<root vartype="array" xml_encode_version="1.0">
<var vartype="integer" varname="integeritem">1</var>
<var vartype="string" varname="stringitem">stringvalue</var>
<var vartype="double" varname="floatitem">1</var>
<var vartype="array" varname="arrayitems">
<var vartype="string" varname="0">arrayvalue1</var>
<var vartype="string" varname="1">arrayvalue2</var>
</var>
<var vartype="array" varname="hashitems">
<var vartype="string" varname="hashkey1">hashkey1value</var>
<var vartype="string" varname="hashkey2">hashkey2value</var>
</var>
<var vartype="NULL" varname="literalnull" />
<var vartype="integer" varname="literalbool">1</var>
<var vartype="object" varname="objectitem">
<var vartype="string" varname="stringitem">stringvalue</var>
<var vartype="integer" varname="integeritem">1</var>
<var vartype="integer" varname="floatitem">1</var>
<var vartype="array" varname="arrayitems">
<var vartype="string" varname="0">arrayvalue1</var>
<var vartype="string" varname="1">arrayvalue2</var>
</var>
<var vartype="array" varname="hashitems">
<var vartype="string" varname="hashkey1">hashkey1value</var>
<var vartype="string" varname="hashkey2">hashkey2value</var>
</var>
<var vartype="NULL" varname="literalnull" />
<var vartype="integer" varname="literalbool">1</var>
</var>
</root>
*/
キー名は varname 属性 (html エンコード) に格納され、型も格納されるため、対称的な逆シリアル化が可能であることに注意してください。これには 1 つだけ問題があります。クラスはシリアル化されず、インスタンス化されたオブジェクトのみがシリアル化され、クラス メソッドは含まれません。これは、「データ」をやり取りする場合にのみ機能します。
これはずっと前に答えられましたが、これが誰かに役立つことを願っています。
まあ、少し汚いですが、オブジェクトのプロパティでいつでもループを実行できます...
$_xml = '';
foreach($obj as $key => $val){
$_xml .= '<' . $key . '>' . $val . '</' . $key . ">\n";
}
$_xml
fopen / fwrite / fcloseを使用すると、変数をコンテンツとして使用してXMLドキュメントを生成できます。それは醜いですが、それはうまくいくでしょう。