Saya fungsi di bawah ini, saya berjuang untuk mengeluarkan DOMDocument tanpa menambahkan pembungkus tag XML, HTML, body dan p sebelum output konten. Perbaikan yang disarankan:
$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));
Hanya berfungsi jika konten tidak memiliki elemen level blok di dalamnya. Namun, jika ya, seperti pada contoh di bawah ini dengan elemen h1, keluaran yang dihasilkan dari saveXML dipotong ke ...
<p> Jika Anda suka </p>
Saya telah diarahkan ke posting ini sebagai solusi yang mungkin, tetapi saya tidak dapat memahami cara menerapkannya ke dalam solusi ini (lihat upaya berkomentar di bawah).
Ada saran?
function rseo_decorate_keyword($postarray) {
global $post;
$keyword = "Jasmine Tea"
$content = "If you like <h1>jasmine tea</h1> you will really like it with Jasmine Tea flavors. This is the last ocurrence of the phrase jasmine tea within the content. If there are other instances of the keyword jasmine tea within the text what happens to jasmine tea."
$d = new DOMDocument();
@$d->loadHTML($content);
$x = new DOMXpath($d);
$count = $x->evaluate("count(//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and (ancestor::b or ancestor::strong)])");
if ($count > 0) return $postarray;
$nodes = $x->query("//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and not(ancestor::h1) and not(ancestor::h2) and not(ancestor::h3) and not(ancestor::h4) and not(ancestor::h5) and not(ancestor::h6) and not(ancestor::b) and not(ancestor::strong)]");
if ($nodes && $nodes->length) {
$node = $nodes->item(0);
// Split just before the keyword
$keynode = $node->splitText(strpos($node->textContent, $keyword));
// Split after the keyword
$node->nextSibling->splitText(strlen($keyword));
// Replace keyword with <b>keyword</b>
$replacement = $d->createElement('strong', $keynode->textContent);
$keynode->parentNode->replaceChild($replacement, $keynode);
}
$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));
// $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->item(1));
// $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->childNodes);
return $postarray;
}
sumber
DOMDocument
yang juga mempengaruhi kode dalam jawaban ini. Afaik,DOMDocument
selalu mengartikan data masukan sebagai latin-1 kecuali jika masukan menentukan rangkaian karakter yang berbeda . Dengan kata lain:<meta charset="…">
Tag tampaknya diperlukan untuk memasukkan data yang bukan latin-1. Jika tidak, output akan rusak, misalnya karakter multibyte UTF-8.Hapus saja node secara langsung setelah memuat dokumen dengan loadHTML ():
sumber
<!DOCTYPE
karya. Baris kedua putus jika<body>
memiliki lebih dari satu catatan anak.Gunakan
saveXML()
sebagai gantinya, dan teruskan documentElement sebagai argumen untuk itu.http://php.net/domdocument.savexml
sumber
saveHTML
juga ( contoh )loadHTML
libxml menggunakan modul pengurai HTML dan itu akan memasukkan kerangka HTML yang hilang. Akibatnya,$dom->documentElement
akan menjadi elemen HTML root. Saya telah memperbaiki kode contoh Anda. Sekarang harus melakukan apa yang diminta Scott.Masalah dengan jawaban teratas adalah itu
LIBXML_HTML_NOIMPLIED
tidak stabil .Ia dapat menyusun ulang elemen (terutama, memindahkan tag penutup elemen atas ke bawah dokumen), menambahkan
p
tag acak , dan mungkin berbagai masalah lainnya [1] . Ini dapat menghapus taghtml
danbody
untuk Anda, tetapi dengan mengorbankan perilaku yang tidak stabil. Dalam produksi, itu adalah bendera merah. Pendeknya:Jangan gunakan
LIBXML_HTML_NOIMPLIED
. Sebagai gantinya, gunakansubstr
.Pikirkan tentang itu. Panjang
<html><body>
dan</body></html>
ditetapkan dan di kedua ujung dokumen - ukurannya tidak pernah berubah, begitu pula posisinya. Ini memungkinkan kita menggunakansubstr
untuk memotongnya:( INI BUKAN SOLUSI TERAKHIR NAMUN! Lihat di bawah untuk jawaban lengkapnya , terus membaca untuk konteksnya)
Kami memotong
12
dari awal dokumen karena<html><body>
= 12 karakter (<<>>+html+body
= 4 + 4 + 4), dan kami mundur dan memotong 15 dari bagian akhir karena\n</body></html>
= 15 karakter (\n+//+<<>>+body+html
= 1 + 2 + 4 + 4 + 4)Perhatikan bahwa saya masih menggunakan
LIBXML_HTML_NODEFDTD
omit the!DOCTYPE
from sedang disertakan. Pertama, ini menyederhanakansubstr
penghapusan tag HTML / BODY. Kedua, kami tidak menghapus doctype dengansubstr
karena kami tidak tahu apakah 'default doctype
' akan selalu menjadi sesuatu dengan panjang tetap. Tapi, yang terpenting,LIBXML_HTML_NODEFDTD
menghentikan pengurai DOM dari menerapkan jenis dokumen non-HTML5 ke dokumen - yang setidaknya mencegah pengurai memperlakukan elemen yang tidak dikenali sebagai teks lepas.Kami tahu pasti bahwa tag HTML / BODY memiliki panjang dan posisi yang tetap, dan kami tahu bahwa konstanta seperti
LIBXML_HTML_NODEFDTD
itu tidak pernah dihapus tanpa pemberitahuan penghentian, jadi metode di atas akan berjalan dengan baik di masa mendatang, TAPI ...... satu-satunya peringatan adalah bahwa penerapan DOM dapat mengubah cara penempatan tag HTML / BODY di dalam dokumen - misalnya, menghapus baris baru di akhir dokumen, menambahkan spasi di antara tag, atau menambahkan baris baru.
Ini dapat diperbaiki dengan mencari posisi dari tag pembuka dan penutup
body
, dan menggunakan offset tersebut untuk memangkas panjang kami. Kami menggunakanstrpos
danstrrpos
untuk menemukan offset dari depan dan belakang, masing-masing:Sebagai penutup, pengulangan dari jawaban final, bukti masa depan :
Tanpa doctype, tanpa tag html, tanpa tag body. Kami hanya berharap pengurai DOM akan segera menerima lapisan cat baru dan kami dapat langsung menghilangkan tag yang tidak diinginkan ini.
sumber
$html = $dom -> saveHTML();
-$dom -> saveHTML();
ulang?Trik yang rapi adalah dengan menggunakan
loadXML
dan kemudiansaveHTML
. Thehtml
danbody
tag dimasukkan diload
panggung, bukansave
panggung.NB bahwa ini agak hacky dan Anda harus menggunakan jawaban Jonah jika Anda bisa membuatnya berfungsi.
sumber
gunakan DOMDocumentFragment
sumber
Ini tahun 2017, dan untuk Pertanyaan 2011 ini, saya tidak suka jawabannya. Banyak regex, kelas besar, loadXML dll ...
Solusi mudah yang memecahkan masalah yang diketahui:
Mudah, Sederhana, Solid, Cepat. Kode ini akan berfungsi terkait tag HTML dan pengkodean seperti:
Jika ada yang menemukan kesalahan, tolong beritahu, saya akan menggunakan ini sendiri.
Edit , Opsi valid lainnya yang berfungsi tanpa kesalahan (sangat mirip dengan yang sudah diberikan):
Anda bisa menambahkan body sendiri untuk mencegah hal-hal aneh pada furure.
Opsi tiga:
sumber
mb_convert_encoding
dan sebagai gantinya menambahkan<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body>
dan memodifikasisubstr
sesuai. Btw, milikmu adalah solusi paling elegan di sini. Suara positif.Saya sedikit terlambat dalam klub, tapi tidak ingin tidak berbagi metode yang saya sudah tahu tentang. Pertama-tama saya punya versi yang tepat untuk loadHTML () untuk menerima opsi bagus ini, tetapi
LIBXML_HTML_NOIMPLIED
tidak berfungsi pada sistem saya. Juga pengguna melaporkan masalah dengan parser (misalnya di sini dan di sini ).Solusi yang saya buat sebenarnya cukup sederhana.
HTML yang akan dimuat diletakkan di file
<div>
elemen sehingga memiliki wadah yang berisi semua node yang akan dimuat.Kemudian elemen kontainer ini dihapus dari dokumen (tapi DOMElementnya masih ada).
Kemudian semua turunan langsung dari dokumen tersebut akan dihapus. Ini termasuk setiap tambahan
<html>
,<head>
dan<body>
tag (LIBXML_HTML_NOIMPLIED
opsi efektif ) serta<!DOCTYPE html ... loose.dtd">
deklarasi (efektifLIBXML_HTML_NODEFDTD
).Kemudian semua turunan langsung dari penampung ditambahkan ke dokumen lagi dan dapat menjadi keluaran.
XPath bekerja seperti biasa, berhati-hatilah karena sekarang ada beberapa elemen dokumen, jadi bukan satu node root:
sumber
Tidak ada solusi lain pada saat penulisan ini (Juni, 2012) yang dapat sepenuhnya memenuhi kebutuhan saya, jadi saya menulis solusi yang menangani kasus-kasus berikut:
<doctype>
,<xml>
,<html>
,<body>
, dan<p>
tag)<p>
sendiri.Jadi, inilah solusi yang memperbaiki masalah tersebut:
Saya juga menulis beberapa tes yang akan dilakukan di kelas yang sama:
Anda dapat memeriksa apakah itu berfungsi untuk Anda sendiri.
DomDocumentWorkaround::testAll()
mengembalikan ini:sumber
Oke saya menemukan solusi yang lebih elegan, tetapi hanya membosankan:
Baiklah, semoga ini tidak menghilangkan apa-apa dan membantu seseorang?
sumber
Gunakan fungsi ini
sumber
preg_replace
karena menggunakan metode berbasis DOMDocument untuk menghapus tag html dan tubuh tidak mempertahankan pengkodean UTF-8 :(Jika solusi bendera yang dijawab oleh Alessandro Vendruscolo tidak berfungsi, Anda dapat mencoba ini:
$bodyTag
akan berisi kode HTML Anda yang diproses secara lengkap tanpa semua pembungkus HTML tersebut, kecuali untuk<body>
tag, yang merupakan root dari konten Anda. Kemudian Anda dapat menggunakan regex atau fungsi trim untuk menghapusnya dari string terakhir (setelahsaveHTML
) atau, seperti dalam kasus di atas, mengulang semua anak-anaknya, menyimpan konten mereka ke dalam variabel sementara$finalHtml
dan mengembalikannya (apa yang saya yakini sebagai lebih aman).sumber
Saya berjuang dengan ini di RHEL7 yang menjalankan PHP 5.6.25 dan LibXML 2.9. (Barang lama di tahun 2018, saya tahu, tapi itu Red Hat untuk Anda.)
Saya telah menemukan bahwa banyak solusi yang diberi suara positif yang disarankan oleh Alessandro Vendruscolo merusak HTML dengan mengatur ulang tag. Yaitu:
menjadi:
Ini berlaku untuk kedua opsi yang dia sarankan untuk Anda gunakan:
LIBXML_HTML_NOIMPLIED
danLIBXML_HTML_NODEFDTD
.Solusi yang disarankan oleh Alex berjalan setengah jalan untuk menyelesaikannya, tetapi tidak berhasil jika
<body>
memiliki lebih dari satu simpul anak.Solusi yang berhasil untuk saya adalah berikut ini:
Pertama, untuk memuat DOMDocument, saya menggunakan:
Untuk menyimpan dokumen setelah memijat DOMDocument, saya menggunakan:
Saya orang pertama yang setuju bahwa ini bukanlah solusi yang sangat elegan - tetapi berhasil.
sumber
Menambahkan
<meta>
tag akan memicu perilaku perbaikan dariDOMDocument
. Bagian baiknya adalah Anda tidak perlu menambahkan tag itu sama sekali. Jika Anda tidak ingin menggunakan pengkodean pilihan Anda, teruskan saja sebagai argumen konstruktor.http://php.net/manual/en/domdocument.construct.php
Keluaran
Terima kasih kepada @Bart
sumber
Saya juga memiliki persyaratan ini, dan menyukai solusi yang diposting oleh Alex di atas. Namun, ada beberapa masalah - jika
<body>
elemen tersebut berisi lebih dari satu elemen turunan, dokumen yang dihasilkan hanya akan berisi elemen turunan pertama saja<body>
, tidak semuanya. Juga, saya membutuhkan stripping untuk menangani hal-hal secara kondisional - hanya ketika Anda memiliki dokumen dengan judul HTML. Jadi saya menyempurnakannya sebagai berikut. Alih-alih menghapus<body>
, saya mengubahnya menjadi a<div>
, dan menghapus deklarasi XML dan<html>
.sumber
Sama seperti anggota lain, saya pertama kali menikmati kesederhanaan dan kekuatan luar biasa dari jawaban @Alessandro Vendruscolo. Kemampuan untuk hanya meneruskan beberapa konstanta yang ditandai ke konstruktor tampaknya terlalu bagus untuk menjadi kenyataan. Bagi saya itu. Saya memiliki versi yang benar dari LibXML serta PHP namun tidak peduli apa itu tetap akan menambahkan tag HTML ke struktur simpul dari objek Dokumen.
Solusi saya bekerja jauh lebih baik daripada menggunakan ...
Bendera atau ....
Penghapusan Node, yang menjadi berantakan tanpa urutan terstruktur di DOM. Sekali lagi, fragmen kode tidak memiliki cara untuk menentukan struktur DOM.
Saya memulai perjalanan ini dengan menginginkan cara sederhana untuk melakukan traversal DOM bagaimana JQuery melakukannya atau setidaknya dengan cara tertentu yang memiliki kumpulan data terstruktur baik yang terhubung secara tunggal, terhubung ganda atau traversal simpul pohon. Saya tidak peduli berapa lama saya bisa mengurai string seperti yang dilakukan HTML dan juga memiliki kekuatan luar biasa dari properti kelas entitas node untuk digunakan di sepanjang jalan.
Sejauh ini DOMDocument Object telah membuat saya menginginkan ... Seperti banyak programmer lain, sepertinya ... Saya tahu saya telah melihat banyak frustrasi dalam pertanyaan ini jadi sejak AKHIRNYA .... (setelah kira-kira 30 jam mencoba dan gagal jenis pengujian) Saya telah menemukan cara untuk mendapatkan semuanya. Saya harap ini membantu seseorang ...
Pertama, saya sinis terhadap SEMUANYA ... lol ...
Saya akan pergi seumur hidup sebelum setuju dengan siapa pun bahwa kelas pihak ketiga tetap diperlukan dalam kasus penggunaan ini. Saya sangat banyak dan saya BUKAN penggemar menggunakan struktur kelas pihak ketiga namun saya tersandung ke parser yang hebat. (sekitar 30 kali di Google sebelum saya menyerah jadi jangan merasa sendirian jika Anda menghindarinya karena terlihat payah tidak resmi dengan cara apa pun ...)
Jika Anda menggunakan fragmen kode dan membutuhkan, kode bersih dan tidak terpengaruh oleh parser dengan cara apa pun, tanpa menggunakan tag tambahan, gunakan simplePHPParser .
Luar biasa dan bertindak sangat mirip dengan JQuery. Saya tidak sering terkesan tetapi kelas ini menggunakan banyak alat yang bagus dan saya belum memiliki kesalahan penguraian sampai saat ini. Saya sangat menyukai kemampuan untuk melakukan apa yang dilakukan kelas ini.
Anda dapat menemukan file-nya untuk diunduh di sini , petunjuk permulaannya di sini , dan API-nya di sini . Saya sangat merekomendasikan menggunakan kelas ini dengan metode sederhana yang dapat melakukan cara
.find(".className")
yang sama seperti metode pencarian JQuery akan digunakan atau bahkan metode yang sudah dikenal sepertigetElementByTagName()
ataugetElementById()
...Ketika Anda menyimpan pohon simpul di kelas ini, itu tidak menambahkan apa-apa. Anda cukup mengatakan
$doc->save();
dan mengeluarkan seluruh pohon ke string tanpa keributan.Saya sekarang akan menggunakan parser ini untuk semua, non-capped-bandwidth, project di masa mendatang.
sumber
Saya memiliki PHP 5.3 dan jawaban di sini tidak berhasil untuk saya.
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
mengganti semua dokumen dengan hanya anak pertama, saya memiliki banyak paragraf dan hanya yang pertama yang disimpan, tetapi solusi memberi saya titik awal yang baik untuk menulis sesuatu tanparegex
saya meninggalkan beberapa komentar dan saya cukup yakin ini dapat ditingkatkan tetapi jika seseorang memiliki masalah yang sama dengan saya, ini bisa menjadi titik awal yang baik.Kemudian kita bisa menggunakannya seperti ini:
Perhatikan bahwa
appendChild
menerima aDOMNode
jadi kita tidak perlu membuat elemen baru, kita cukup menggunakan kembali yang sudah ada yang menerapkanDOMNode
sepertiDOMElement
ini penting untuk menjaga kode "waras" saat memanipulasi beberapa dokumen HTML / XMLsumber
LIBXML_HTML_NOIMPLIED
seperti yang dilakukannya hanya sebagian. Menghapus doctype secara efektifLIBXML_HTML_NODEFDTD
.Saya menemukan topik ini untuk menemukan cara menghapus pembungkus HTML. Menggunakan
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
berfungsi dengan baik, tetapi saya memiliki masalah dengan utf-8. Setelah banyak usaha saya menemukan solusi. Saya mempostingnya di bawah untuk siapa pun yang memiliki masalah yang sama.Masalahnya disebabkan karena
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Masalah:
Solusi 1:
Solusi 2:
sumber
Saya menghadapi 3 masalah dengan
DOMDocument
kelas.1- Kelas ini memuat html dengan encoding ISO dan karakter utf-8 tidak muncul dalam keluaran.
2- Bahkan jika kita memberikan
LIBXML_HTML_NOIMPLIED
bendera untuk metode loadHtml, sampai html masukan kami tidak mengandung tag root, itu tidak akan mengurai dengan benar.3- Kelas ini menganggap tag HTML5 tidak valid.
Jadi saya telah mengganti kelas ini untuk menyelesaikan masalah ini dan saya mengubah beberapa metode.
Sekarang saya menggunakan
DOMEditor
alih-alihDOMDocument
dan sejauh ini berhasil dengan baik untuk sayasumber
Saya menemukan masalah ini juga.
Sayangnya, saya tidak merasa nyaman menggunakan solusi apa pun yang disediakan di utas ini, jadi saya pergi untuk memeriksa salah satu yang akan memuaskan saya.
Inilah yang saya buat dan berfungsi tanpa masalah:
Intinya, ini bekerja dengan cara yang mirip dengan sebagian besar solusi yang disediakan di sini, tetapi alih-alih melakukan kerja manual, ia menggunakan pemilih xpath untuk memilih semua elemen di dalam tubuh dan menggabungkan kode html mereka.
sumber
descendant-or-self::body/p/*
.server saya mendapat php 5.3 dan tidak dapat memutakhirkan jadi opsi itu
bukan untuk saya.
Untuk mengatasi hal ini saya memberi tahu Fungsi SaveXML untuk mencetak elemen Body dan kemudian hanya mengganti "body" dengan "div"
ini kode saya, semoga bisa membantu seseorang:
utf-8 adalah untuk dukungan Ibrani.
sumber
Jawaban Alex benar, tetapi mungkin menyebabkan kesalahan berikut pada node kosong:
Ini dia mod kecil saya:
Menambahkan trim () juga merupakan ide bagus untuk menghapus spasi.
sumber
Saya mungkin terlambat. Tetapi mungkin seseorang (seperti saya) masih memiliki masalah ini.
Jadi, semua hal di atas tidak berhasil untuk saya. Karena $ dom-> loadHTML juga menutup tag terbuka, tidak hanya menambahkan tag html dan body.
Jadi menambahkan elemen <div> tidak berfungsi untuk saya, karena terkadang saya menyukai 3-4 div yang tidak ditutup di bagian html.
Solusi saya:
1.) Tambahkan spidol untuk dipotong, lalu muat potongan html
2.) lakukan apapun yang Anda inginkan dengan dokumen
3.) simpan html
4.) sebelum dikembalikan, hapus tag <p> </ p> dari marker, anehnya hanya muncul di [MARK] tapi tidak di [/ MARK] ...!?
5.) Hapus semua sebelum dan sesudah penanda
6.) mengembalikannya
Akan jauh lebih mudah jika LIBXML_HTML_NOIMPLIED bekerja untuk saya. Itu skema, tapi sebenarnya tidak. PHP 5.4.17, libxml Versi 2.7.8.
Saya merasa sangat aneh, saya menggunakan parser DOM HTML dan kemudian, untuk memperbaiki "hal" ini saya harus menggunakan regex ... Intinya adalah, bukan menggunakan regex;)
sumber
< div >< div > ... < /div >
. Saya masih mencari solusi.Bagi siapa pun yang menggunakan Drupal, ada fungsi bawaan untuk melakukan ini:
https://api.drupal.org/api/drupal/modules!filter!filter.module/function/filter_dom_serialize/7.x
Kode untuk referensi:
sumber
Anda dapat menggunakan tidy dengan show-body-only:
Tapi, ingat: bersihkan beberapa tag seperti ikon Font Awesome: Masalah Mengindentasi HTML (5) dengan PHP
sumber
sumber
Pustaka ini mempermudah untuk melintasi / memodifikasi DOM dan juga menangani penghapusan pembungkus doctype / html untuk Anda:
https://github.com/sunra/php-simple-html-dom-parser
sumber