Pendahuluan (Pengenalan Latar Belakang):
Apache PoI adalah proyek open source berikutnya dari Apache Foundation, yang digunakan untuk memproses dokumen dalam seri Office dan dapat membuat dan menguraikan dokumen dalam format Word, Excel, dan PPT.
Ada dua teknologi untuk memproses dokumen kata, yaitu HWPF (.doc) dan XWPF (.docx). Jika Anda terbiasa dengan dua teknologi ini, Anda harus dapat memahami rasa sakit menggunakan Java untuk mengurai dokumen kata.
Dua masalah terbesar adalah:
Yang pertama adalah bahwa kedua kelas ini tidak memiliki kelas induk terpadu dan antarmuka (XSSF dan HSSF di sebelahnya menatap mata mereka yang menghina), sehingga mereka tidak dapat melakukan pemrograman antarmuka dalam format yang sama;
Yang kedua adalah bahwa tidak ada antarmuka untuk posisi relatif gambar dalam dokumen di API resmi, yang mengarah pada fakta bahwa meskipun Anda dapat memperoleh semua gambar dalam dokumen, Anda tidak dapat mengetahui di mana gambar -gambar ini berada. Di masa depan, Anda tidak akan dapat memasukkan gambar di posisi yang benar.
Untuk poin pertama, saya tidak punya pilihan selain mempelajari teknologi terkait lainnya, seperti Jacob, Doc4j, dll., Untuk melihat apakah ada solusi lain, tetapi DOC4J tampaknya dapat memproses dokumen 2007 (.docx).
Untuk poin kedua, artikel ini akan memberi saya solusi penulis. Bahkan, ini juga tujuan penulisan saya artikel ini.
Catatan: Lihat saja Bab 2 dan Bab 3 jika Anda hanya meminta kecepatan;
1. Pengetahuan Persiapan
1. Dua format dokumen kata sesuai dengan dua metode penyimpanan yang berbeda
Seperti yang kita semua tahu, dokumen Word memiliki dua format penyimpanan: DOC dan DOCX
DOC: Biasanya disebut Word2003, yang menggunakan data penyimpanan biner ; Ini bukan fokus diskusi kita hari ini.
DOCX: Word2007, menggunakan XML untuk menyimpan data dan format.
Mungkin Anda akan bertanya, mengapa format XML jelas merupakan dokumen yang berakhir di DOCX?
Ini sangat sederhana: Anda bisa memilih file docx, klik kanan untuk membukanya dengan alat kompresi, dan Anda bisa mendapatkan struktur direktori seperti ini:
Jadi Anda pikir DOCX adalah dokumen lengkap, tetapi sebenarnya itu hanya file terkompresi. (docx :? _?)
2. Format definisi XML dalam dokumen Word:
Dari contoh sebelumnya, kami belajar bahwa dokumen DOCX menggunakan file terkompresi, yaitu XML untuk menggambarkan data. Jadi bagaimana data dalam dokumen Word didefinisikan secara khusus?
Karena ruang, seluruh dokumen terkompresi tidak akan dijelaskan secara rinci di sini. Saya hanya akan memperkenalkan dua file/folder secara singkat:
Pertama, file Document.xml di Direktori Word, yang merupakan definisi dari seluruh konten dokumen;
Yang kedua adalah folder media di Direktori Word. Anda dapat menebak konten multimedia dalam dokumen dengan melihat nama:
Gambar 3: Word/document.xml (Tentukan konten dokumen)
Gambar 4: Isi di bawah folder Word/Media
Berikut ini adalah beberapa konten kunci dari dokumen dokumen.xml:
A: Dokumen Definisi Struktur Keseluruhan:
<W: Dokumen MC: IaNTABLE = "W14 W15 WP14" XMLNS: M = "http://schemas.openxmlformats.org/officedocument/2006/math" xmlns: mc = "http://schemas.openxmats. "cmark. xmlns: o = "urn: schemas-microsoft-com: kantor: kantor" xmlns: r = "http://schemas.openxmlformats.org/officedocument/2006/relationships" xmlns: v = "urn: schemas-microsoft: vlns": "schemas-comrosoft: xmlns" xmlns: w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns: w10 = "urn: schemas-microsoft-kom: word" xmlns: w14 = "http:/schormlon (words.mlns. xmlns: w15 = "http://schemas.microsoft.com/office/word/2012/wordml" xmlns: wne = "http://schemas.microsoft.com/office/2006/wordml" xmlns: wp = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingdrawing" xmlns: wp14 = "http://schemas.microsoft.com/word" xmlns: wpg = "http://schemas.microsoft.com/office/word/2010/wordprocessingcanvas" xmlns: wpg = "http://schemas.microsoft.com/office/word/word/2010/word" xmlns: wpi = "http://schemas.microsoft.com/office/word/2010/wordprocessingink" xmlns: wps = "http://schemas.microsoft.com/office/word/2010/wordprocessingshape" " xmlns:wpscustomdata="http://www.wps.cn/officeDocument/2013/wpsCustomData"> <w:body> <w:p> <w:ppr> <w:pstyle w:val="2"> </w:pstyle> <w:keepnext w:val="0"> </w:keepnext> <W: Keeplines w: val = "0"> </w: Keeplines> <W: WidowControl> </w: WidowControl> <W: Suppresslinenumbers W: Val = "0"> </w: Suppresslinenumbers> <w: pbdr> <W: TOT W: color = "auto" w: space = "0 <W: Kiri W: Color = "Auto" W: Space = "0" W: Val = "None"> </w: Bottom> <W: Right W: Color = "Auto" W: Space = "0" W: SZ = "0" W: Val = "None"> </W: Right> </w: pbdr>
B: Dokumen Paragraf Konten:
<W: p> <w: ppr> <w: pstyle w: val = "2"> </w: pstyle> <w: Keepnext w: val = "0"> </w: KeepNext> <W: Keeplines W: Val = "0"> </w: Keeplines> <w: WidowCrol> <W: W: "w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w: w valumbers <w: w: w: w: w: w: w: w: w: w: w: w valumbers <w: widrowcrol> <w: walpowccon> walproles: w: w valumbers <w: w valumsres </w: Suppresslinenumbers> <w: pbdr> <w: top w: color = "auto" w: space = "0" w: sz = "0"> </w: top> <w: kiri w: color = "auto" w: space = "0" w: sz = "0" W: val = "none"> </w: left "w: sz =" 0 "W: val =" none "> </w: left" w: sz = "0" w: val = "none"> </w: left "w: sz =" W: w: val = "none"> </w: we: w: sz = w: w: val = "none"> </w: we: w: sz = w: w: val = "none"> </w left W: sz = "0" w: val = "none"> </w: bottom> <w: right w: color = "auto" w: space = "0" w: sz = "0" w: val = "none"> </w: right> </w: pbdr> <w: w: iff = "fafafa" w: val = "clear"> </whd: w: shd w: fill = "fafafa" w: val = "clear"> </w: w: shd w: fill = "fafafa" w: val = "clear"> </w: w: shd w: fill = "fafafa" w: val = "clear"> W: afterAutospacing = "0" w: sebelum = "150" w: beForeautospacing = "0" w: line = "378" w: linerule = "atleast"> </w: spacing> <w: ind w: firstline = "0" w: kiri = "0" w: right = "0"> </w: ind> W: ASCII = "Verdana" W: CS = "Verdana" W: Hansi = "Verdana" W: Hint = "Default"> </w: rfonts> <w: iw: val = "0"> </w: i> <w: caps w: val = "0"> </w: caps> <w: val: wale = "404 w:val="0"> </w:spacing> <w:sz w:val="21"> </w:sz> <w:szcs w:val="21"> </w:szcs> </w:rpr> </w:ppr> <w:rpr> <w:rpr> <w:rpr> <w:rfonts w:ascii="Verdana" w:cs="Verdana" w:hansi="Verdana" w:hint="default"> </w:rfonts> <w:iw:val="0"> </w:i> <w:caps w:val="0"> </w:caps> <w:color w:val="404040"> </w:color> <w:spacing w:val="0"> </w: spasi> <w: sz w: val = "21"> </w: sz> <w: szcs w: val = "21"> </w: szcs> <w: bdr w: color = "auto" w: space = "0" w: sz = "0" w: val = "none"> </w: bdr> "w: sz =" 0 "w: val =" none "> </w: bdr> </w: shd> </w: rpr> <w: t> penulis: brian sayang </w: t> </w: r> </w: p>
C: Definisi Konten Gambar:
<w:r> <w:rpr> <w:rfonts w:ascii="Verdana" w:cs="Verdana" w:hansi="Verdana" w:hint="default"> </w:rfonts> <w:iw:val="0"> </w:i> <w:caps w:val="0"> </w:caps> <w:color W: val = "404040"> </w: color> <w: spacing w: val = "0"> </w: spacing> <w: sz w: val = "21"> </w: sz> <w: szcs w: val = "21"> </w: szcs> <w: bdr w: auto = "a." W: val = "None"> </w: bdr> <w: shd w: fill = "fafafa" w: val = "clear"> </w: shd> </w: rpr> <w: drawing> <wp: inline distb = "0" disl = "114300" dist = "114300" distb = "0"> <"quad" 54300 "54300" cy="5543550"> </wp:extent> <wp:effectextent b="0" l="0" r="0" t="0"> </wp:effectextent> <wp:docpr descr="IMG_256" id="1" name="Picture 1"> </wp:docpr> <wp:cnvgraphicframepr> <a:graphicframelocks noChangeaspect = "1" xmlns: a = "http://schemas.openxmlformats.org/drawingml/2006/main"> </a: grafikframelocks> </wp: cnvgraphicFramepr> <a: grafik xmlns: a = "http://schemas.openxmlformats.org/drawingml/2006/main"> <a: graphicdata uri = "http://schemas.openxmlformats.org/drawingml/2006/spicture"> piceMlform xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"> <pic:nvpicpr> <pic:cnvpr descr="IMG_256" id="1" name="Picture 1"> </pic:cnvpr> <pic:cnvpicpr> <a:piclocks noChangeaspect = "1"> </a: piclocks> </pic: cnvpicpr> </pic: nvpicpr> <pic: blipfill> <a: blip r: embed = "rid4"> </a: blip> <a: stretch> <a: fillrect> </a: fillrect> </a: a: pic: pic: fillrect> </a: fillrect> </a: a: pic: picfon> </picfrect <a:off x="0" y="0"> </a:off> <a:ext cx="5543550" cy="5543550"> </a:ext> </a:xfrm> <a:prstgeom prst="rect"> <a:avlst> </a:avlst> </a:prstgeom> <a:nofill> </a:nofill> <a: ln w = "9525"> <a: nofill> </a: nofill> </a: ln> </pic: sppr> </pic: pic> </a: graphicdata> </a: grafik> </wp: inline> </w: drawing> </w: r>
Jika Anda tertarik, Anda dapat melihat tiga kode XML di atas. Saya akan memberikan kesimpulan langsung di sini:
Word Document Shema File: xmlns: w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
Dokumen Root Node: <W: Document> mendefinisikan awal seluruh dokumen
<W: Body> adalah simpul anak dari dokumen dan konten utama dokumen
<W: p> node anak tubuh, paragraf, adalah paragraf dalam dokumen Word
<W: R> Node anak elemen P, Run mendefinisikan paragraf dengan format yang sama dalam paragraf
<W: T> Node anak dari simpul elemen run adalah konten dokumen.
<W: Drawing> Node anak dari elemen run, mendefinisikan gambar:
<W: inline> Menggambar node anak, tidak ada penelitian mendalam yang dilakukan pada aplikasi spesifik.
<A: Graphic> Tentukan konten gambar
<pic: blipfill> Ini adalah simpul anak dari dokumen grafis, yang mendefinisikan indeks konten gambar. Secara khusus, POI dapat memperoleh sumber daya yang sesuai dari gambar berdasarkan nama ini, dan kunci untuk mendapatkan lokasi gambar dokumen ada di sini.
Secara keseluruhan, dokumen DOCX Parsing XWPF adalah untuk menguraikan dokumen XML, menyimpan semua node, dan kemudian mengubahnya menjadi properti yang lebih berguna, menyediakan API untuk digunakan pengguna.
Jadi kami dapat menggunakan antarmuka yang diberikan kepada kami oleh POI untuk mendapatkan konten dokumen, menguraikan data dalam dokumen sendiri, dan mendapatkan paragraf yang ada di. Tentu saja, Anda juga dapat mengetahui elemen run mana yang terletak di belakang.
2. Realisasi
Paket com.szdfhx.reportstatistic.util; import com.microsoft.schemas.vml.ctshape; import org.apache.poi.xwpf.usermodel.xwpfparagraph; import orgache.poi.xwpf.usermodel.xwficel org.apache.poi.xwpf.usermodel.xwpfrun; impor org.apache.xmlbeans.xmlcursor; impor org.apache.xmlbeans.xmlObject; impor org.openxmlformats.schemas.drawingml.x2006.mgrectors. org.openxmlformats.schemas.drawingml.x2006.picture.ctpicture; impor org.openxmlformats.schemas.drawingml.x2006.main.ctdrawing; import.openxmlformss.schemas.wordprocesing org.openxmlformats.schemas.wordprocessingml.x2006.main.ctr; import java.util.arraylist; import java.util.list; import java.util.list; get looks puba public; gets in puba public; readImageInparagraph (paragraf XWPFParagraph) {// Daftar Indeks Gambar <String> ImageBundLeList = ArrayList baru <String> (); // semua daftar xwpfrun <XWPFrun> di paragraf runlist = paragraf.getRuns (); untuk (xwpfrun run: runlist) {// xwpfrun adalah atributnya sendiri yang dihasilkan oleh POI setelah parsing elemen XML. Itu tidak dapat diuraikan melalui XML. Itu perlu dikonversi menjadi Ctr Ctr Ctr = run.getCtr (); // Transaksi Elemen Anak XMLCursor C = Ctr.NewCursor (); // Ini untuk mendapatkan semua elemen anak: C.SelectPath ("./*"); while (c.tonextselection ()) {xmlObject o = c.getObject (); // Jika elemen anak dalam bentuk <w: drawing>, gunakan ctdrawing untuk menyimpan gambar jika (o contoh ctdrawing) {ctdrawing drawing = (ctdrawing) o; Ctinline [] ctinlines = drawing.getInlineArray (); untuk (ctinline ctinline: ctinlines) {ctgraphicalObject graphic = ctinline.getGraphic (); // xmlcursor kursor = graphic.getGraphicData (). NewCursor (); kursor.selectpath ("./*"); while (Cursor.TonextSelection ()) {xmlObject xmlObject = cursor.getObject (); // Jika elemen anak ada dalam bentuk <pic: pic> if (xmlObject instance dari ctpicture) {org.openxmlformats.schemas.drawingml.x2006.picture.ctpicture picture = (org.openxmlformss.schemas.drawingmmlingmmlingmling.x20066 // Dapatkan atribut elemen ImageBundLeList.Add (picture.getBlipFill (). GetBlip (). GetEMbed ()); }}}}} // Gunakan ctObject untuk menyimpan gambar // <w: object> form if (o instance dari ctObject) {ctObject objek = (ctObject) o; System.out.println (objek); Xmlcursor w = Object.newCursor (); W.SelectPath ("./*"); while (w.tonextselection ()) {xmlObject xmlObject = w.getObject (); if (xmlObject instance dari ctshape) {ctshape bentuk = (ctshape) xmlObject; ImageBundLeList.Add (shape.getImagedataArray () [0] .getId2 ()); }}}}} return ImageBundLeList; }}Pertama -tama, kita perlu mengusulkan enkapsulasi elemen XML oleh XWPF:
<W: Dokumen> sesuai dengan kelas XWPFDocument
<W: Run> sesuai dengan kelas XWPFRUN
Pada dasarnya, itu hanya sesuai dengan lapisan lari. Karena ada banyak elemen anak lari, tidak ada lagi enkapsulasi dan definisi pada tingkat berikut.
Jadi kita hanya bisa mendapatkan semua objek XWPFRUN yang dikonversi menjadi definisi XML -nya: Objek CTR. Akhirnya, gunakan CTR untuk membaca dan menguraikan isi elemen run dan mendapatkan indeks gambar.
Hal kedua yang perlu dibicarakan adalah definisi seluruh elemen XML:
Kita dapat melihat bahwa POI menggunakan XML yang diuraikan oleh teknologi XMLBeans di bawah Apache. Jika Anda tidak membahas teknologi terkait secara mendalam, Anda harus memahami dua poin utama:
1: Semua elemen dalam dokumen XML dienkapsulasi oleh XMLBEAN dan mewarisi antarmuka XMLObject, sehingga kelas ini dapat digunakan untuk menerima elemen anak yang diperoleh;
2: Elemen Traversal dilakukan melalui XMLCursor. Akuisisi spesifik elemen anak dikontrol berdasarkan atribut PilihPath dari objek XMLCursor. Ketika selectpath adalah "./*", itu didefinisikan sebagai elemen anak yang melintasi;
Jadi ditulis sebagai berikut: Ini dapat melintasi elemen anak dari elemen saat ini dan memeriksa jenis elemen anak:
Ctr Ctr = run.getctr (); // Transulasi elemen anak XMLCursor c = ctr.newcursor (); // Ini untuk mendapatkan semua elemen anak: C.SelectPath ("./*"); while (c.tonextselection ()) {xmlObject o = c.getObject (); // Jika elemen anak ada dalam bentuk <w: drawing>, gunakan ctdrawing untuk menyimpan gambar jika (o contoh ctdrawing) {ctdrawing drawing = (ctdrawing) o;Akhirnya, Anda mungkin memiliki pertanyaan, bukankah elemen ini <W: Drawing> mendefinisikan gambar?
Jadi
if (o instance dari ctObject) {ctObject objek = (ctObject) o; ...}Untuk apa kondisi penilaian kedua digunakan?
Anda seharusnya menebaknya
Itu benar! Selain <W: Drawing>, XML dalam dokumen DOCX juga dapat digunakan untuk menentukan gambar.
Mengapa hanya ada keduanya?
Karena saya hanya menggunakan metode pertama untuk menguraikan, saya menemukan bahwa beberapa gambar hilang, jadi saya menemukan metode kedua ... mungkin ada lebih dari dua? Lagipula saya tidak tahu, tidak ada masalah bagi saya saat ini.
Mungkin Anda, siapa yang pintar, telah menghadapi lebih banyak situasi dalam praktik?
Kemudian, menggunakan metode parsing XML yang disebutkan di atas, saya yakin Anda dapat membacanya dengan benar dan mendapatkan nilai indeks yang Anda inginkan.
Perluas sedikit. Jika ada API lain yang tidak disediakan oleh POI, dapatkah kita juga mengimplementasikannya melalui teknologi parsing XML? Ini mengharuskan kita untuk mengeksplorasi dalam praktik. Saya percaya bahwa waktu akan memberi kita jawabannya.
Oke, sekarang kita memiliki nilai indeks, jadi bagaimana kita mendapatkan sumber daya gambar?
POI menyediakan metode siap pakai:
Ada getPictureDataByID (gambar string) di kelas XWPFDocument;
Metode ini bisa mendapatkan objek XWPFPICTREDATE, yang merupakan sumber daya gambar.
Untuk operasi tertentu, silakan merujuk ke posting blog yang relevan dan API, yang tidak akan diperkenalkan secara rinci di sini.
3. Tes:
Kode untuk menguji menggunakan Junit4:
Paket com.szdfhx.reportstatistic.util; impor org.apache.commons.collections.collectionutils; import org.apache.commons.lang.stringutils; impor org.apache.poi.xwpf.usermodel.xwpfdocument; org.apache.poi.xwpf.usermodel.xwpfaragraph; impor org.apache.poi.xwpf.usermodel.xwpfpicturedata; impor org.junit.test; impor java.fileinputStream; impor java.io.ooxception; java.util.collections; import java.util.list; impor static org.junit.assert.*; kelas publik xwpfutilstest {@test void readimageInparagraph () lemparan ioException {inputStream in = new fileInputStream ("D://My Document/My ParsStream/Parsing WordeInping (" D://My Document/My Document/My Document/Document/My Document/Document/My Document/Document/Document/My Document/Document/Document/Document/My Document/Document/Document/My Document/Dokumen/Dokumen/My My Blog/ParsStream New dokumen // example.docx "); Xwpfdocument xwpfdocument = xwpfdocument baru (IN); Daftar <XWPFParagraph> paragraflist = xwpfdocument.getParagraphs (); System.out.println ("Indeks Gambar/T | Nama Gambar/T | Konten paragraf teks pada gambar/t"); System.out.pringln("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ if (collectionsils.isnotempty (ImageBundLeList)) {for (String pictureID: ImageBundLeList) {xwpfpictureData picture paragraflist.get (i-1) .getParagraphText ();Menunjukkan hasil:
Penggunaan nama gambar di sini berarti bahwa saya telah memperoleh sumber daya yang sesuai. Bahkan, jika Anda terbiasa dengan konten artikel sebelumnya, Anda akan menemukan bahwa nama gambar sebenarnya adalah nama lengkap dari semua gambar di folder Word/Media.
Dalam objek XWPFPicturedata yang sesuai, data biner gambar dapat diperoleh melalui properti getData (), sehingga Anda dapat menyimpannya ke database atau folder lokal Anda!
4. Lainnya:
Berbicara tentang hal ini, masalah kedua yang disebutkan di awal telah diselesaikan di sini.
Jadi, apa yang harus saya lakukan dengan pertanyaan pertama?
Jika sistem Anda tidak memerlukan kecepatan tinggi, maka saran saya adalah untuk mengubah dokumen dokumen menjadi dokumen DOCX untuk diurai - POI memiliki API yang matang untuk dilakukan
Jika Anda ingin mempertimbangkan kinerja, Anda harus menulis dua set metode untuk menguraikan dokumen.
Jadi ... bagaimana mendapatkan posisi relatif gambar dalam dokumen kata tipe DOC?
Saya tidak tahu ... atau, datang dan beri tahu saya?
Dalam kata parsing Java di atas, metode untuk mendapatkan lokasi gambar dalam dokumen adalah semua konten yang saya bagikan dengan Anda. Saya harap Anda dapat memberi Anda referensi dan saya harap Anda dapat mendukung wulin.com lebih lanjut.