2013-04-07 30 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