在PHP中将JSON/类似css的格式化字符串转换为XML


Convert JSON/CSS-like Formated String to XML in PHP

是否可以将格式化字符串转换为PHP中的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"
    )
);

谢谢。

因为输入数据的格式很好,所以可以创建一个非常简单的递归后代解析器—甚至不涉及那么多递归。或者只使用简单的堆栈:

$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');

解决方案:-)

$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);

应该可以了

$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>';

我的解决方案:

我尝试使用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);

谢谢。