序文(バックグラウンドはじめに):
Apache Poiは、Officeシリーズのドキュメントを処理するために使用されるApache Foundationの次のオープンソースプロジェクトであり、Word、Excel、およびPPT形式でドキュメントを作成および解析することができます。
ワードドキュメントを処理するための2つのテクノロジー、つまりHWPF(.DOC)とXWPF(.DOCX)があります。これら2つのテクノロジーに精通している場合は、Javaを使用して単語文書を解析する痛みを理解できるはずです。
最大の問題の2つは次のとおりです。
1つ目は、これらの2つのクラスに統一された親クラスとインターフェイス(XSSFとHSSFの隣のHSSFが軽empt的な目をキャストしていない)がないため、同じ形式でインターフェイスプログラミングを実行できないことです。
2つ目は、公式APIのドキュメント内の写真の相対的な位置のインターフェイスがないことです。これは、ドキュメント内のすべての写真を取得できますが、これらの写真がどこにあるかを知ることができないという事実につながります。将来、写真を正しい位置に挿入することはできません。
最初の点では、Jacob、Doc4Jなどの他の関連技術を研究して、他のソリューションがあるかどうかを確認する以外に選択肢はありませんが、Doc4Jは2007ドキュメント(.DOCX)を処理できるようです。
2番目のポイントについては、この記事で著者の解決策を教えてくれます。実際、これは私がこの記事を書いている目的でもあります。
注:単に速度を求めている場合は、第2章と第3章を見てください。
1。準備知識
1.単語文書の2つの形式は、2つの異なるストレージメソッドに対応しています
私たち全員が知っているように、Word Documentsには2つのストレージ形式があります:docとdocx
Doc:バイナリストレージデータを使用するWord2003と呼ばれます。これは今日の私たちの議論の焦点ではありません。
DOCX:Word2007は、 XMLを使用してデータと形式を保存します。
たぶん、あなたは尋ねるでしょう、なぜそれは明らかにDOCXで終わるドキュメントであるXML形式なのでしょうか?
非常に簡単です。Docxファイルを選択し、右クリックして圧縮ツールで開くことができます。このようなディレクトリ構造を取得できます。
したがって、Docxは完全なドキュメントだと思いますが、実際には単なる圧縮ファイルです。 (docx:?_?)
2。単語文書のXMLの定義形式:
前の例から、DOCXドキュメントは圧縮ファイル、つまりXMLを使用してデータを説明することを学びました。では、Word文書のデータは具体的にどのように定義されていますか?
スペースのため、圧縮ドキュメント全体について詳しく説明しません。 2つのファイル/フォルダーを簡単に紹介します。
まず、ドキュメントコンテンツ全体の定義であるWord Directoryのdocument.xmlファイル。
2つ目は、Word Directoryのメディアフォルダーです。名前を見ると、ドキュメント内のマルチメディアコンテンツを推測できます。
図3:word/document.xml(ドキュメントコンテンツを定義)
図4:Word/Mediaフォルダーの下の内容
以下は、document.xmlドキュメントの重要な内容です。
A:全体的な構造定義を文書化:
<w:document mc:無知= "w14 w15 wp14" xmlns:m = "http://schemas.openxmlformats.org/officedocument/2006/math" xmlns:mc = "http://schemas.openxmlformatsmlformats.org/markup-compatiuiifuiy/2006" xmlns:o = "urn:schemas-microsoft-com:office:office" xmlns:r = "http://schemas.openxmlformats.org/officedocument/2006/relationships" xmlns:v = "urn:schemas-misoft-com:vml xmlns:w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10 = "urn:schemas-microsoft-com:Office:word" xmlns:w14 = "http://schemas.microsoft.com xmlns:w15 = "http://schemas.microsoft.com/office/word/2012/wordml" xmlns:wne = "http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wp = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingdrawing" xmlns:wp14 = "http://schemas.microsoft.com/office/word/2010/wordprocessingddrawing" xmlns:wpg = "http://schemas.microsoft.com/office/word/2010/wordprocessingingcanvas" xmlns:wpg = "http://schemas.microsoft.com/office/word/2010/wordprocessinginggroop" 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:w:pstyle W:val = "2"> </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:wientlines w:val = "0"> </w:keeplines> <w:widowcontrol> </w:widowcontrol> <w:suppresslinenumbers W:val = "0"> </w:suppresslineNumbers> <w:pbdr> <w:w:w:coler = "colo" <w:左w:color = "auto" w:space = "0" w:val = "none"> </w:bottom> <w:右w:color = "auto" w:space = "0" w:sz = "0" w:val = "> </w:右> </w:pbdr>
B:文書段落の内容:
<W:P> <W:PPR> <W:PSTYLE W:VAL = "2"> </W:PSTYLE> <W:KEEPNEXT W:VAL = "0"> </w:KeepNext> <W:Val = "0> </W:Keeplines> <W:WidowControl> </w:suppresslineNumbers> <w:pbdr> <w:w:color = "auto" w:space = "0" w:sz = "0"> </w:top> <w:左w:color = "auto" w: "0" w:sz = "0"> w:val = "none"> w:w:w: "" w:sz = "0" w:val = "none"> </w:bottom> <w:右w:color = "auto" w:space = "0" w:sz = "0" w:val = "none"> </w:pbdr> <w:shd w:fill = "fafafa" w:bal = "> </w:"> </w: " w:andautospacing = "0" w:before = "150" w:beforeautospacing = "0" w:line = "378" w:linerule = "atleast"> </w:ind w:firstline = "0" w:left = "0" w:right = "0" W:ascii = "Verdana" w:cs = "Verdana" w:hansi = "Verdana" W:hint = "default"> </w:rfonts> <w:iw:val = "0"> </w:i> <w:w:val = "0"> </w W:val = "0"> </w:間隔> <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:rfonts w:rfonts w:rfonts w:rfonts w:rfonts w:rfonts w:rfonts w:rfonts w:rfonts w:rfonts w:rfonts w:ascii W:cs = "Verdana" W:hansi = "Verdana" W:hint = "default"> </w:rfonts> <w:val = "0"> </w:i> <w:bal = "0> </w:caps> <w:color w:val =" 404040 "> </w:" </w:間隔> <w:sz w:val = "21"> </w:sz> <w:szcs w:val = "21"> </w:szcs> <w:bdr w:color = "auto" w: "0" w:sz = "0" w:val = "none" none " </w:shd> </w:rpr> <w:t>著者:ブライアン親愛なる</w:t> </w:r> </w:p>
C:画像コンテンツの定義:
<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:val = "404040"> </w:color> <w:coler> <w:val = "0"> </w:sz w:sz w:val = "21"> </w:sz> <w:szcs w:val = "21"> </w:szcs> <w:bdd W:val = "none"> </w:bdr> <w:shd w:fill = "fafafa" w:val = "clear"> </w:shd> </w:rpr> <w:drawing> <wp:inline distb = "0" distl = "114300" dist = "114300" Cy = "5543550"> </wp:extens> <wp:effectextent b = "0" l = "" r = "0" t = "0"> </wp:effectextent> <wp:docpr descr = "img_256" id = "1" name = "picture 1"> </wp nochangeaspect = "1" xmlns:a = "http://schemas.openxmlformats.org/drawingml/2006/main"> </a:graghicframeLocks> </wp:cnvgraphicframepr> <a:graghic xmlns:a = "http://schemas.openxmlformats.org/drawingml/2006/main"> <a:graphicdata uri = "http://schemas.openxmlformats.org/drawingml/2006/picture"> <pic xmlns:pic = "http://schemas.openxmlformats.org/drawingml/2006/picture"> <pic:nvpicpr> <pic:cnvpr descr = "img_256" id = "1" name = "pictue 1" nochangeaspect = "1"> </a:piclocks> </pic:cnvpicpr> </pic:nvpicpr> <pic:blipfill> <a:blip r:embed = "rid4"> </a:blip> <a:streate> <a:fillrect> </a:fillrect> </a:slett> </pic <a:xfrm> <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:ln w = "9525"> <a:nofill> </a:nofill> </a:ln> </pic:sppr> </pic:pic> </a:graphicdata> </a:graphic> </wp:inline> </w:描画
興味がある場合は、上記の3つのXMLコードを見ることができます。ここで直接結論を出します:
word document shemaファイル:xmlns:w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
ドキュメントルートノード:<w:document>ドキュメント全体の開始を定義します
<w:body>はドキュメントの子ノードであり、ドキュメントの主な内容です
<w:p>段落であるボディチャイルドノードは、単語文書の段落です
<w:r> p要素の子ノード、実行は段落に同じ形式の段落を定義します
<w:t>実行要素ノードの子ノードは、ドキュメントのコンテンツです。
<W:W:描画>実行要素の子ノード、画像を定義します。
<w:inline>子ノードの描画では、特定のアプリケーションに関する詳細な研究は行われていません。
<A:グラフィック>画像コンテンツを定義します
<pic:blipfill>これは、画像コンテンツのインデックスを定義するグラフィックドキュメントの子ノードです。具体的には、POIはこの名前に基づいて画像の対応するリソースを取得でき、ドキュメント画像の場所を取得するための鍵はこちらです。
全体として、XWPF解析DOCXドキュメントは、XMLドキュメントを解析し、すべてのノードを保存し、より有用なプロパティに変換し、ユーザーが使用できるAPIを提供することです。
したがって、POIが提供するインターフェイスを使用してドキュメントコンテンツを取得し、ドキュメントのデータを自分で解析し、画像がどの段落にあるかを取得できます。もちろん、画像がどのランニング要素にあるかを知ることもできます。
2。実現
パッケージcom.szdfhx.reportstatistic.util; Import com.microsoft.schemas.vml.ctshape; Import org.apache.poi.xwpf.usermodel.xwpfparaph; Import org.apache.poi.xwpf.usermodel.xwppteuredAta; org.apache.poi.xwpf.usermodel.xwpfrun; Import org.apache.xmlbeans.xmlcursor; Import org.apache.xmlbeans.xmlobject; Import org.openxmlformats.schemas.drawingml.x2006.main.ctgraphicerobject; Import; org.openxmlformats.drawingml.x2006.picture.ctpicture; import org.openxmlformats.schemas.drawingml.x2006.main.ctdrawing; import org.openxmlformats.schemas. org.openxmlformats.schemas.wordprocessingml.x2006.main.ctr; import java.util.arraylist; import java.util.list; import java.util.list; import java.util.map; public class xwpfutils { /emag readimageinparagraph(xwpfparagraph paragraph){// image index list <string> imagebundlelist = new ArrayList <String>(); //すべてのxwpfrunリスト<xwpfrun>段落runlist = paragraph.getruns(); for(xwpfrun run:runlist){// xwpfrunは、XML要素を解析した後にPOIによって生成される独自の属性です。 XMLを介して解析することはできません。 Ctr ctr ctr = run.getctr()に変換する必要があります。 //子要素のトランザクションxmlcursor c = ctr.newcursor(); //これは、すべての子供の要素を取得するためです。C.SelectPath( "./*"); while(c.tonextselection()){xmlobject o = c.getobject(); //子要素が<w:描画>の形である場合、ctdrawingを使用して画像を保存します(o ctdrawing){ctdrawing drawing =(ctdrawing)o; ctinline [] ctinlines = drawing.getinlinearray(); for(ctinline ctinline:ctinlines){ctgraphicalobject graphic = ctinline.getgraphic(); // xmlcursor cursor = graphic.getgraphicdata()。newcursor(); cursor.selectpath( "./*"); while(cursor.tonextselection()){xmlobject xmlobject = cursor.getObject(); //子要素がフォームにある場合<pic:pic> if(xmlobject instance of ctpicture){org.openxmlformats.schemas.drawingml.x2006.picture.ctpicture picture =(org.openxmlformats.schemas.drawingml.x2006.picture; ctpicture; // elementの属性を取得しますimagebundlelist.add(picture.getblipfill()。getBlip()。getembed()); }}}}} // ctobjectを使用して画像// <w:object> form if(o instanceof ctobject){ctobject object =(ctobject)o; system.out.println(object); xmlcursor w = object.newcursor(); W.SelectPath( "./*"); while(w.tonextselection()){xmlobject xmlobject = w.getobject(); if(xmlobject instance of ctshape){ctshape shape =(ctshape)xmlobject; imagebundlelist.add(shape.getimagedataarray()[0] .getid2()); }}}}} return imagebundleList; }}まず、XWPFによるXML要素のカプセル化を提案する必要があります。
<w:document> xwpfdocumentクラスに対応しています
<w:run> xwpfrunクラスに対応しています
基本的に、それは実行層にのみ対応します。実行には多くの子要素があるため、次のレベルでカプセル化と定義はなくなりました。
したがって、XML定義に変換されたすべてのXWPFRUNオブジェクトのみを取得できます:CTRオブジェクト。最後に、CTRを使用して、実行要素の内容を読み取り、解析し、画像のインデックスを取得します。
2番目に話すのは、XML要素全体の定義です。
POIは、Apacheの下でXMLBEANSテクノロジーによって解析されたXMLを使用していることがわかります。関連するテクノロジーについて詳しく説明しない場合は、2つの重要なポイントを理解する必要があります。
1:XMLドキュメントのすべての要素はXMLBeanによってカプセル化され、Xmlobjectインターフェイスを継承するため、このクラスを使用して取得した子供要素を受信できます。
2:要素トラバーサルはXmlcursorを介して行われます。子要素の特定の取得は、XMLCursorオブジェクトのSelectPath属性に基づいて制御されます。 SelectPathが「./*」の場合、子要素を横断するものとして定義されます。
したがって、次のように書かれています。現在の要素の子要素を通過し、子要素のタイプを確認できます。
ctr ctr = run.getctr(); //子要素を透過xmlcursor c = ctr.newcursor(); while(c.tonextselection()){xmlobject o = c.getobject(); //子要素がフォーム<w:描画>の場合、ctdrawingを使用して画像を保存します(o ctdrawing){ctdrawing drawing =(ctdrawing)o;最後に、質問があるかもしれませんが、この要素<w:描画>は画像を定義しませんでしたか?
それで
if(o instanceof ctobject){ctobject object =(ctobject)o; ...}使用される2番目の判断条件は何ですか?
あなたはそれを推測すべきだった
それは正しい! <W:描画>に加えて、DOCXドキュメントのXMLを使用して画像を定義することもできます。
なぜこれら2つだけがいるのですか?
私は最初の方法だけを使用したので、いくつかの写真が失われたことがわかりましたので、2番目の方法が見つかりました...多分2つ以上あるのでしょうか?とにかく、私は知りません、現時点では私には問題ありません。
おそらく、賢い人は、実際により多くの状況に遭遇したのでしょうか?
次に、上記のXML解析方法を使用して、それを正しく読んで、必要なインデックス値を取得できると思います。
少し広げます。 POIによって提供されていない他のAPIがある場合、XML解析テクノロジーを介してそれらを実装することもできますか?これには、実際に探索する必要があります。私はその時間が私たちに答えを与えると信じています。
さて、今ではインデックス値がありますので、どのようにして画像リソースを取得できますか?
POIは既製の方法を提供します:
XWPFDocumentクラスには、getpicturedAtabyid(string picture)があります。
このメソッドは、画像リソースであるXWPFPICTRUEDATEオブジェクトを取得できます。
特定の操作については、関連するブログ投稿とAPIを参照してください。ここでは詳細に紹介しません。
3。テスト:
junit4を使用してテストするコード:
パッケージcom.szdfhx.reportstatistic.util; Import org.apache.commons.comlections.collectionutils; import org.apache.commons.lang.stringutils; Import org.apache.poi.xwpf.usermodel.xwpfdocument; Import org.apache.poi.xwpf.usermodel.xwpfparagraph; Import org.apache.poi.xwpf.usermodel.xwpfpicturedata; Import org.junit.test; Import java.io.fileinputstream; Import Java.io.io.Io.Io.Io.Io.IO.IO.IO.IO.IO.IO.IO.IO.IO.IO.IO.IO.IO.IO.IO.IOCEPTING; java.util.collections; import java.util.list; import static org.junit.assert。*; public class xwpfutilstest {@test public void readimageinparagraph()throws ioexception {inputstream in = new fileinputstream(d:// document // document // example.docx "); xwpfdocument xwpfdocument = new xwpfdocument(in);リスト<xwpfparagraph> paragraphlist = xwpfdocument.getParagraphs(); System.out.println( "Image Index/T | Image name/t |画像/t"のテキストの段落のコンテンツ); System.out.pringln("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ if(collectutils.isnotempty(imagebundlelist)){for(string pictureid:imagebundlelist){xwpfpicturedata picturedata = xwpfdocument.getPicturedatabyid(PictureId); paragraphlist.get(i-1).getparagraphtext();結果を表示:
ここでの画像名の使用は、対応するリソースを取得したことを意味します。実際、前の記事の内容に精通している場合、画像の名前は実際には単語/メディアフォルダーのすべての画像のフルネームであることがわかります。
対応するXWPFPICTUREDATAオブジェクトでは、画像のバイナリデータをgetData()プロパティを介して取得できるため、データベースまたはローカルフォルダーに保存できます。
4。その他:
これについて言えば、最初に言及された2番目の問題はここで解決されました。
それで、私は最初の質問をどうすればいいですか?
システムが高速を必要としない場合、私のアドバイスはDoc DocumentをDocxドキュメントに変換して解析することです-POIには成熟したAPIがあります
パフォーマンスを検討したい場合は、ドキュメントを解析するために2セットのメソッドを記述する必要があります。
それで...ドキュメントタイプのWordドキュメントで画像の相対的な位置を取得するにはどうすればよいですか?
わからない...または、来て教えてくれますか?
上記のJava解析語では、ドキュメント内の画像の場所を取得する方法は、私があなたと共有するすべてのコンテンツです。参照を提供できることを願っています。wulin.comをもっとサポートできることを願っています。