2013-04-07 121 views
0

是否可以在PHP中將格式化的字符串轉換爲xml格式或數組?我有字符串格式是這樣的:在PHP中將JSON/CSS類似的字符串轉換爲XML

$prop = " 
    large { 
     width: 10px; 
     height: 10px; 
    } 
    small { 
     width: 5px; 
     height: 5px; 
    } 
"; 

我想這個字符串轉換爲XML格式或陣列,如:

<large> 
    <width>10px</width> 
    <height>10px</height> 
</large> 
<small> 
    <width>5px</width> 
    <height>5px</height> 
</small> 

$array = array(
    "large" => array(
     "width" => "10px", 
     "height" => "10px" 
    ), 
    "small" => array(
     "width" => "5px", 
     "height" => "5px" 
    ) 
); 

感謝。

+0

格式符合什麼條件?實際上,如果這是CSS,那麼數組不能工作,因爲可能有重複的鍵。 – hakre 2013-04-07 11:44:35

+0

這不適用於CSS。我會將它們用於我的應用程序屬性,如配置等。上面的鍵只是示例。要閱讀我使用'read('config.debugger.debug_mode');'的屬性。我這樣做是爲了簡化財產分配並簡化財產的閱讀。另外'read()'函數可以在任何地方使用,所以我不需要使用$ GLOBALS ['config'];謝謝。 – 2013-04-07 12:34:42

+0

很高興知道,看起來像CSS一樣。當你問這個問題添加這樣的上下文時,這也是一個好主意。例如。你可以使用第一個存在的東西,比如屬性文件或yaml。甚至只是一個數組。至於你的解決方案:請把它從問題轉移到答案。這是正確的方法,解決方案不屬於這個問題。 – hakre 2013-04-07 12:37:11

回答

0

這應該工作

$elements = explode('}', trim($prop)); 
for($i = 0 ; $i < sizeof($elements); $i++) { 
    list($name, $styles) = explode('{', $elements[$i]); 
    $name = trim($name); 
    if(empty($name)) { 
     continue; 
    } 
    $rules = explode(';', $styles); 
    for($j=0; $j < sizeof($rules); $j++) { 
     list($ruleName, $ruleVal) = explode(':', $rules[$j]); 
     $ruleName = trim($ruleName); 
     if(empty($ruleName)) { 
      continue; 
     } 
     $result[$name][$ruleName] = trim($ruleVal); 
    } 
} 
echo '<pre>'; 
var_dump($result); 
echo '</pre>'; 
+0

謝謝@Freeman Latif,但它不起作用。嘗試使用格式化字符串構建多維數組,但它失敗 – 2013-04-07 10:02:58

+0

我剛剛嘗試過它,它可以工作,你能告訴我你得到的錯誤信息嗎? – 2013-04-07 10:08:30

+0

是的,它可以在上面的例子中用'$ prop'工作。創建具有3維格式的新格式,並且代碼將無法工作 – 2013-04-07 10:57:26

1

解決方案,它:-)

$prop = " 
    large { 
     width: 10px; 
     height: 10px; 
     color: red; 
    } 
    small { 
     width: 5px; 
     height: 5px; 
    } 
    medium { 
     width: 5px; 
     height: 5px; 
    } 
"; 

//remove carriage return 
$prop = str_replace(array('.', ' ', "\n", "\t", "\r"), '', $prop); 

//get into main names and values 
preg_match_all('/([^\{]+)\{([^\}]+)\}/i',$prop,$matches); 

$arr_names = $matches[1]; 
$arr_values = $matches[2]; 

$arr_result = array(); 
foreach($arr_names as $i=>$name){ 
    $value = $arr_values[$i]; 

    //get into main sub names and values 
    preg_match_all('/([^\:]+)\:([^\;]+)\;/i',$value,$m); 
    $arr_n = $m[1]; 
    $arr_v = $m[2]; 

    $arr = array(); 
    foreach($arr_n as $j=>$n){ 
     $v = $arr_v[$j]; 
     $arr[$n] = $v; 
    } 

    $arr_result[$name] = $arr; 
} 

print_r($arr_result); 
+0

是的,它適用於2維格式,但不適用於3維或更多維度。我嘗試使用'button-> large-> bound-> width'創建新格式並失敗。但是我已經用'preg_replace'和'eval()'找到了我的解決方案,並且適用於多維格式。謝謝。 – 2013-04-07 11:15:32

+0

好 - 太糟糕了,你沒有寫在你的問題! – Adidi 2013-04-07 12:33:42

4

的工作,因爲你的輸入數據被很好地格式化您可以創建一個非常簡單的遞歸後裔解析器 - 即使沒有那麼多的遞歸參與其中。或者只是一個簡單的堆棧:

$props = array_filter(array_map('trim', explode("\n", $prop))); 
$stack = [$node = $xml = new SimpleXMLElement('<root/>')]; 

foreach ($props as $str) 
{ 
    if ($str === '}') { 
     array_pop($stack); 
     $node = end($stack); 
     continue; 
    } 

    if (preg_match('~^(\w+) {$~', $str, $matches)) { 
     $node = $stack[] = $node->addChild($matches[1]); 
     continue; 
    } 

    if (preg_match('~^(\w+):\s*(.*)$~', $str, $matches)) { 
     $node->addChild($matches[1], htmlspecialchars($matches[2])); 
     continue; 
    } 

    throw new UnexpectedValueException(sprintf('Unable to parse: "%s"', $str)); 
} 

$xml->asXML('php://output'); 

你的第二個例子(以前失蹤),然後是(美化)輸出:

<?xml version="1.0"?> 
<root> 
    <button> 
    <large> 
     <bond> 
     <width>10px;</width> 
     <height>10px;</height> 
     </bond> 
     <style> 
     <background> 
      <color>#ffffff;</color> 
      <image>url(www.px.com/aui.png) -10px;</image> 
      <another> 
      <width>100px;</width> 
      <height>100px;</height> 
      </another> 
     </background> 
     </style> 
    </large> 
    <small> 
     <bond> 
     <width>10px;</width> 
     <height>10px;</height> 
     </bond> 
     <style> 
     <color>#fff;</color> 
     <border>1px solid #000;</border> 
     </style> 
    </small> 
    </button> 
</root> 

我建議你使用XML這裏,因爲它可以代表結構更好比不能有重複鍵的數組。

也可以使用遞歸函數調用而不是堆棧。但是這需要來包裝輸入流中的無倒帶迭代器不會打破(或使用array_shift,但我不喜歡那麼多):

$parse = function($p, SimpleXMLElement $t) use (&$parse) { 
    foreach($p as $s) { 
     if ($s === '}') { 
      break; 
     } 

     if (preg_match('~^([^ ]+) {$~', $s, $m)) { 
      $p->next(); 
      $parse($p, $t->addChild($m[1])); 
      continue; 
     } 

     if (preg_match('~^([^:]+):\s*(.*)$~', $s, $m)) { 
      $n = $t->addChild($m[1], htmlspecialchars($m[2])); 
      continue; 
     } 
    } 
}; 

$props = array_filter(array_map('trim', explode("\n", $prop))); 
$xml = new SimpleXMLElement('<root/>'); 
$parse(new NoRewindIterator(new ArrayIterator($props)), $xml); 

$xml->asXML('php://output'); 
+0

非常感謝你@hakre,這是我正在尋找的。 :) – 2013-04-07 12:55:29

-1

我的解決方案:

我嘗試使用preg_replace()eval(),並使用多維格式。也許你可以改進我的preg_replace模式。

$string = " 
    button { 
     large { 
      bond { 
       width: 10px; 
       height: 10px; 
      } 
      style { 
       background { 
        color: #ffffff; 
        image: url(www.px.com/aui.png) -10px; 
        another { 
         width: 100px; 
         height: 100px; 
        } 
       } 
      } 
     } 
     small { 
      bond { 
       width: 10px; 
       height: 10px; 
      } 
      style { 
       color: #fff; 
       border: 1px solid #000; 
      } 
     } 
    } 
"; 

$string = preg_replace("/(\s+\:)/", ':', $string); 
$string = preg_replace("/(\:\s+)/", ':', $string); 
$string = preg_replace("/(\s+\{)/", '{', $string); 

$string = preg_replace("/([\w\d_]+)\:(.*?)\;/", '"$1" => "$2",', $string); 
$string = preg_replace("/([\w\d_]+)\{/", '"$1" => array (', $string); 
$string = preg_replace("/\}/", ')', $string); 

$string = preg_replace("/\"\,(\s+)\)/", '"$1)', $string); 
$string = preg_replace("/\)(\s+)\"/", '),$1"', $string); 

$arr = eval('return array('.$string.');'); 
print_r($arr); 

謝謝。

+0

eval不是一個好的選擇(在這裏),它可以結束你的腳本,如果發生錯誤並且很危險(http://php.net/manual/en/function.eval.php)。 – pce 2013-04-07 12:54:36

+0

@pce:謝謝。我以前不知道。我嘗試使用'$ arr = array($ string)',但它的索引是'$ arr [0] => array'。 :( – 2013-04-07 13:01:34

+0

哦,非常感謝你,你的輝煌。:)我可以編輯這個答案嗎? :) – 2013-04-07 13:10:23