2013-03-21 19 views
9

<p> etiketinin içine sarılması gereken tüm kök düzey #text düğümlerini (veya ebeveyn ebeveynleri olan) bulmak istiyorum. Aşağıdaki metinde, üç (hatta iki tane) son kök <p> etiketi olmalıdır.DOM xpath #text düğümlerini bulmak ve paragraf etiketi içinde sarmak

<div> 
    This text should be wrapped in a p tag. 
</div> 

This also should be wrapped. 

<b>And</b> this. 

fikir metin blokları HTML görüntüsü için paragraflar halinde gruplandırılmış güzel şekilde metni biçimlendirmek etmektir. Ancak, üzerinde çalıştığım aşağıdaki xpath metin düğümlerini seçmekte başarısız görünüyor.

<?php 

$html = '<div> 
    This text should be wrapped in a p tag. 
</div> 

This also should be wrapped. 

<b>And</b> this.'; 

libxml_use_internal_errors(TRUE); 

$dom = DOMDocument::loadHTML($html); 

$xp = new DOMXPath($dom); 

$xpath = '//text()[not(parent::p) and normalize-space()]'; 

foreach($xp->query($xpath) as $node) { 
    $element = $dom->createElement('p'); 
    $node->parentNode->replaceChild($element, $node); 
    $element->appendChild($node); 
} 

print $dom->saveHTML(); 
+3

Ayrıca 'div's dışındaki metin düğümlerini seçmek isterseniz, //ath '' ı XPath ifadenize koydunuz? [Bu keman] (http://codepad.org/hzOefCsH) istediğini yapıyormuş gibi görünüyor. – nwellnhof

+0

Yukarıda kaydettiğim çözümle ilgili sorunun ne olduğunu söyleyebilir misiniz? Metni yeni satırlarla birden çok paragrafa dönüştürmek ister misiniz? – nwellnhof

+0

@nwellnhof, çözümünüz gayet iyi - ama bu bir cevap değil, bu yüzden size hiçbir şey veremem. – Xeoncross

cevap

5

Tamam, bu yüzden yorumumu yanıt olarak yeniden yazayım. Tüm metin düğümlerini eşleştirmek istiyorsanız, XPath ifadenizden //div bölümünü kaldırmanız gerekir. Yani o olur: İsterseniz

//text()[not(parent::p) and normalize-space()] 
+0

Bu,

this text is ok
ile nasıl çalışır? Peki, bu bu? ''? – mzedeler

1

saf JavaScript ile yapabilirsiniz:

var content = document.evaluate(
             '//text()', 
             document, 
             null, 
             XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, 
             null); 

for (var i=0 ; i < content .snapshotLength; i++){ 
    console.log(content .snapshotItem(i).textContent); 
} 
2

Senaryonuz birçok kenar-durumlarda ve üstünde ekliyor gerektiğini kelime var. Klasik modelini yapmak istediğinizi varsayalım, bir çift ara, numaralı yeni bir paragrafı başlatır, ancak bu sefer ebeveynler <div> (veya kesinlikle diğer blok öğeleri) içinde de geçerlidir.

İşin çoğunu HTML ayrıştırıcısına izin veririm, ancak yine de metin aramasıyla çalışır ve değiştiririm (xpath'in yanında). Gelecekte göreceğiniz şey biraz acelecidir ama bence oldukça kararlıdır:

Her şeyden önce, söz konusu divun üst düzey veya alt düzeyindeki tüm metin düğümlerini seçerdim.

(.|./div)/text() 

Bu xpath DOMDocument yüklenen zaman HTML parçasının kök-tag temsil ettiği <body> etikettir bir çapa elemana göre olur.

Eğer bir divun çocuğuysa, o zaman başlangıç ​​paragrafını en baştan yerleştiririm. Yeni bir paragraf başlatır dizinin her bir olayda (burada bir açıklama formunda) bir kırılma işareti eklemek istiyorum her durumda Sonra

(çünkü boşluk normalleşme "\n\n" olmalıdır, yanlış olabilir ve eğer olabilir Bu geçerli değil, bu çalışma şeffaf olması için boşluk boşluk normalleştirme yapmak gerekir. Bunlar takılı kırılma işaretleri sadece orada

/* @var $result DOMText[] */ 
$result = $xp->query('(.|./div)/text()', $anchor); 

foreach ($result as $i => $node) 
{ 
    if ($node->parentNode->tagName == 'div') 
    { 
     $insertBreakMarkBefore($node, true); 
    } 

    while (FALSE !== $pos = strpos($node->data, $paragraphSequence)) 
    { 
     $node = $node->splitText($pos + $paragraphSequenceLength); 
     $insertBreakMarkBefore($node); 
    } 
} 

HTML <p> etiketiyle değiştirilmesi. Bir HTML ayrıştırıcısı bunları yeterli <p>...</p> çiftine dönüştürür, böylece kendimi bu algoritmayı yazabilirim (bu ilginç olsa da). Bu temelde bir kez başka bir cevap özetlenen gibi çalışmak ama sadece linki artık bulmuyorum: DOM ağacının modifikasyonu sonra

  1. tekrar <body> innter HTML olsun.
  2. uygun <p>...</p> çiftiyle DOM yeniden oluşturmak için tekrar
  3. yük ayrıştırıcı içine HTML parçasını (bu görünür yapmak için de sınıf işaretlemek burada) "<p>" ile set izleri değiştirin.
  4. Şimdi en son olan DOMDocument ayrıştırıcısından HTML'yi yeniden edinin.

kodunda Bu aktarılan adımlar, (bir an için işlev tanımlarının bir atlama): Bu görüldüğü gibi

$needle = sprintf('%1$s<!--%2$s-->%1$s', $paragraphSequence, $paragraphComment); 
$replace = sprintf("\n<p class=\"%s\">\n", $paragraphComment); 
$html = strtr($innerHTML($anchor), array($needle . $needle => $replace, $needle => $replace)); 

echo "HTML afterwards:\n", $innerHTML($loadHTMLFragment($html)); 

, çift sekansları tek bir ile değiştirilir. Muhtemelen sonunda bir de silinmesi gerekiyor (eğer uygulamalısınız, ayrıca burada boşlukları da kesebilirsiniz).

nihai HTML çıktı: güzel çıktı biçimlendirme için

<div> 
<p class="break"> 

    This text should be wrapped in a p tag. 
</p> 
</div> 
<p class="break"> 
This also should be wrapped. 
</p> 
<p class="break"> 
<b>And</b> this.</p> 

Biraz daha post-prodüksiyon de yararlı olabilir. Aslında bence algoritmanın ayarlanmasına yardımcı olacağına inanıyorum (Full Demo - sadece görüyorum, boşluk boşluk normalizasyonu muhtemelen orada geçerli değil. Bu yüzden dikkatli kullanın).

+0

Güzel bir açıklama, ancak, demo, aslında bu sonucu elde etmek için görünmüyor. – Xeoncross

+1

Sonunda yazıldığı gibi, bu, eksik boşluk normalleşmesi nedeniyle. Girdinin satır ayırıcı olarak '\ n' kullanıldığından emin olun, kod takımı' \ r \ n' veya simmilar gibi görünüyor, bu yüzden farklı görüyoruz. Bunu daha sonra tekrar kontrol edebilirim, sadece oraya yapıştırdığımda fark ettim, kendi kutuma kod çalışır. Kendiniz için deneyin, zaten kutunuzun üzerinde çalışabilir. – hakre

1

Ben xpath değil biliyorum ama şuna bir bak:

PHP Basit HTML DOM Ayrıştırıcı

http://simplehtmldom.sourceforge.net/

Özellikleri

PHP5 + ile yazılmış bir HTML DOM ayrıştırıcı sen manipüle izin HTML çok kolay bir şekilde!

Geçersiz HTML'yi destekler.

JQuery gibi seçicilere sahip bir HTML sayfasındaki etiketleri bulun.

Tek bir satıra HTML'den içerik alın.

+0

Lütfen cevabınızı bu kütüphaneyle nasıl çalıştığını gösterin, aksi halde bu sadece kısmen ilişkilidir (ve kişisel zevkim için, kütüphane kötü bir öneridir, PHP günümüzde kütüphanenin sunduğu her şeyi barındırır, budur * PHP Basit HTML DOM Parser * kütüphanesi, bugüne kadar mevcut olmadıkları için libxml tabanlı uzantılar olmadan PHP 4 için orijinal olarak yazılmıştır. – hakre

İlgili konular