2012-12-28 26 views
6

Tôi đang cố gắng để phân tích dữ liệu như thế này:PHP: Parsing chỉ namespaced xml

<vin:layout name="Page" xmlns:vin="http://www.example.com/vin"> 
    <header> 
     {someText} 
     <div> 
      <!-- some invalid xml code --> 
      <aas> 
      <nav class="main"> 
       <vin:show section="Menu" /> 
      </nav> 
     </div> 
    </header> 
</vin:layout> 

Làm thế nào tôi có thể phân tích dữ liệu như thế này trong PHP?

Tôi đã thử DOM nhưng không hoạt động, vì xml không đúng định dạng bên trong phần tử gốc. Tôi có thể nói với trình phân tích cú pháp, rằng everithing mà không có không gian tên vin là văn bản?

+0

Bạn cần giải pháp thay thế. Vì [load_invalid_xml] (http://stackoverflow.com/questions/2890120/php-processing-invalid-xml) không hoạt động, tôi sẽ thử một bộ công cụ SGML hoặc có thể là SimpleHtmlDom (chuỗi/dựa trên regex, chứ không phải là libxml). Khi thoát nhanh, hãy xử lý trước nó bằng một regex để chuyển đổi các thẻ không có thẻ tên thành văn bản XML bằng '= preg_replace (" # <((?! /? \ W +: \ w +). *?)> # Smix "," < $ 1 > ", $ xml)'. (Đây là một bình luận để tránh các SO flak điển hình cho thậm chí đề cập đến nó.) – mario

+0

vì lý do gì bạn muốn phân tích cú pháp này, những gì bạn đang cố gắng để làm gì? – GreenRover

+0

Đây là một số loại tệp tempalte. Tất cả các thẻ tên không gian đại diện cho các cuộc gọi hàm. Vì vậy, tôi cần thay thế các thẻ không gian tên bằng một số nội dung khác (văn bản hoặc các thẻ tên không gian khác). Nhưng tôi nghĩ rằng cách duy nhất để đi là sử dụng regex ... – dkoch

Trả lời

1

Tôi có thể sẽ ném một loại trình phân tích cú pháp Thẻoup lên đó. Một cái gì đó có thể đọc định dạng của bạn mà ngoài những thiếu sót trông khá ổn bằng văn bản. Không có gì mà văn bản sẽ ở lại trong cách chống lại một máy quét dựa trên biểu thức chính quy đơn giản. Tôi gọi tôi là Tagsoup chỉ với bốn loại nút bạn có: Starttag, Endtag, Text và Comment. Đối với các Thẻ bạn cần biết về Tên thẻ và NamespacePrefix của chúng. Nó chỉ được đặt tên tương tự như XML/HTML cho convienience, nhưng trên thực tế điều này là tất cả "rool của riêng bạn", do đó, không kéo dài các điều khoản này cho bất kỳ tiêu chuẩn.

Một sử dụng để thay đổi mỗi thẻ (bắt đầu hoặc kết thúc) mà không có tiền tố namespace có thể trông giống như ($string chứa các dữ liệu mà bạn có trong câu hỏi của bạn):

$scanner = new TagsoupIterator($string); 

$nsPrefix = 'vin'; 

foreach ($scanner as $node) { 
    $isTag = $node instanceof TagsoupTag; 
    $isOfNs = $isTag && $node->getTagNsPrefix() === $nsPrefix; 
    if ($isTag && !$isOfNs) { 
     $node = strtr($node, ['&' => '&amp;', '<' => '&lt;']); 
    } 
    echo $node; 
} 

Output:

<vin:layout name="Page" xmlns:vin="http://www.example.com/vin"> 
    &lt;header> 
     {someText} 
     &lt;div> 
      <!-- some invalid xml code --> 
      &lt;aas> 
      &lt;nav class="main"> 
       <vin:show section="Menu" /> 
      &lt;/nav> 
     &lt;/div> 
    &lt;/header> 
</vin:layout> 

Cách sử dụng để trích xuất mọi thứ bên trong một thẻ nhất định của không gian tên có thể trông giống như:

$scanner = new TagsoupIterator($string); 
$parser = new TagsoupForwardNavigator($scanner); 

$startTagWithNsPrefix = function ($namespace) { 

    return function (TagsoupNode $node) use ($namespace) { 

     /* @var $node TagsoupTag */ 
     return $node->getType() === Tagsoup::NODETYPE_STARTTAG 
      && $node->getTagNsPrefix() === $namespace; 
    }; 
}; 

$start = $parser->nextCondition($startTagWithNsPrefix('vin')); 
$tag = $start->getTagName(); 
$parser->next(); 
echo $html = implode($parser->getUntilEndTag($tag)); 

Output:

<header> 
    {someText} 
    <div> 
     <!-- some invalid xml code --> 
     <aas> 
     <nav class="main"> 
      <vin:show section="Menu" /> 
     </nav> 
    </div> 
</header> 

phần tiếp theo là để thay thế một phần của $string. Như TagSoup cung cấp offsets nhị phân và độ dài, điều này rất dễ dàng (và tôi tắt một chút bẩn qua SimpleXML):

$xml = substr($string, 0, $start->getEnd()) . substr($string, $parser->getOffset()); 
$doc = new SimpleXMLElement($xml); 
$doc[0] = $html; 
echo $doc->asXML(); 

Output:

<vin:layout xmlns:vin="http://www.example.com/vin" name="Page"> 
    &lt;header&gt; 
     {someText} 
     &lt;div&gt; 
      &lt;!-- some invalid xml code --&gt; 
      &lt;aas&gt; 
      &lt;nav class="main"&gt; 
       &lt;vin:show section="Menu" /&gt; 
      &lt;/nav&gt; 
     &lt;/div&gt; 
    &lt;/header&gt; 
</vin:layout> 

Tùy thuộc vào bê tông cần điều này sẽ đòi hỏi phải thay đổi việc thực hiện . Ví dụ, điều này sẽ không cho phép đặt cùng một thẻ vào nhau. Nó không ném bạn ra, tuy nhiên nó không xử lý điều đó. Không có ý tưởng nếu bạn có trường hợp đó, nếu như vậy bạn sẽ cần phải thêm một số truy cập mở/đóng, lớp navigator có thể dễ dàng mở rộng cho điều đó, thậm chí để cung cấp hai loại phương pháp tìm kiếm thẻ kết thúc.

Các ví dụ được cung cấp ở đây đang sử dụng Tagsoup mà bạn có thể xem tại gist này: https://gist.github.com/4415105