0

状況は次のとおりです。長い形式の文書のトランスクリプトを表す XML ファイルがいくつかあります。このファイルでは、改ページが void 要素 <pb /> で表記されています。

私がやりたいのは、pb void 要素 (別名自己閉鎖別名シングルトン) で区切られているように、各要素が各「ページ」の有効な XML を表す、ある種のデータ構造体 (配列で問題ありません) を構築することです。

問題は、pb 要素が、任​​意の親ノード内の任意のネスト レベルで表示される可能性がある (実際に表示される) ことです。

私の考えでは、XPath を使用して各 pb 要素を識別し、何らかの方法ですべての要素の親タグを閉じて (ページを終了し)、再度開いて次のページを開始します。PHP DOMXpathを使用しています。

XML の例を次に示します。

<text id="foobar">
 <div type="zing" n="zee">
   <pb n=1 />
   <p>some text</p>
   <p>more text</p>
   <fw><pb n=2 />page 2</fw>
   <p>blah blah</p>
   <p>blah blah blah blah <fw><pb n=3 /></fw> blah</p>
 </div>
</text>

そして、これを次のように変換したいと思います。

<text id="foobar">
 <div type="zing" n="zee">
   <p>some text</p>
   <p>more text</p>
   <fw></fw>
 </div>
</text>
<text id="foobar">
 <div type="zing" n="zee">
   <fw>page 2</fw>
   <p>blah blah</p>
   <p>blah blah blah blah <fw></fw>
  </div>
</text>
<text id="foobar">
 <div type="zing" n="zee">
   <fw></fw> blah</p>
 </div>
</text>

これを行う賢いまたはエレガントな方法を考えている人はいますか?

私が今持っているのは、反復ごとに複数の xpath クエリを持つ別のループ内の再帰ループであり、それはひどいものです。

4

1 に答える 1

0

これが私がこれまでに思いついたものです。私が言ったように、ひどい。

// Given an XML transcript, return an array of pages indexed by <pb> element definitions.
function transcript_to_pages($transcript) {
  $dom = new DOMDocument();

  // 1. Compile the list of pagebreak DOM nodes we're looking for
  // 2. Build a string of all their anscestors
  // 3. chunk the transcript by pagebreaks
  // 4. prepend the ancestor strings to each chunk.
  // 5. build an array of the munged chunks
  $dom->loadHtml($transcript);
  $xpath = new DOMXPath($dom);
  $pbnodes = $xpath->query('//pb');

  $close_string = $open_string = '';
  $i = 0;
  $total = $pbnodes->length;
  foreach ($pbnodes as $pbnode) {
    $page = '';
    $string = $dom->saveXML($pbnode);
    list($page, $transcript) = split($string, $transcript, 2);
    // The first <pb> element should have appeared as the first element of the
    // transcript. This would produce a leading blank page, which we'll skip. 
    if ($i++ == 0) {
      continue;
    }
    if (!empty($open_string)) {
      $page = $open_string . $page;
    }
    $parent = $pbnode->parentNode;
    $close_string = $open_string = '';
    while (!empty($parent)) {
      $close_string .= "</$parent->tagName>";
      $open_tag = "<$parent->tagName";
      if (!empty($parent->attributes)) {
        foreach ($parent->attributes as $key => $value) {
          $val = str_replace('"', '&quot;', $value->value);
          $open_tag .= " $key=\"" . $val . '"';
        }
      }
      $open_tag .= '>';
      $open_string = $open_tag . $open_string;
      if ($parent->tagName == 'text' || empty($parent->parentNode)) {
        break;
      }
      $parent = $parent->parentNode;
    }
    $page .= $close_string;
    $pages[$string] = $page;
  }
  return $pages;
}
于 2013-01-03T22:14:06.270 に答える