0

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

ありがとう。

4

4 に答える 4

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

2番目の例(以前は欠落していた)の出力は(美化されています):

<?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');
于 2013-04-07T12:09:36.200 に答える
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);
于 2013-04-07T10:02:46.197 に答える
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>';
于 2013-04-07T09:33:17.077 に答える