서문 (배경 소개) :
Apache POI는 사무실 시리즈에서 문서를 처리하는 데 사용되는 Apache Foundation의 다음 오픈 소스 프로젝트로 Word, Excel 및 PPT 형식으로 문서를 작성하고 구문 분석 할 수 있습니다.
Word 문서를 처리하기위한 두 가지 기술, 즉 HWPF (.doc) 및 XWPF (.docx)가 있습니다. 이 두 기술에 익숙하다면 Java를 사용하여 단어 문서를 구문 분석하는 고통을 이해할 수 있어야합니다.
가장 큰 두 가지 문제는 다음과 같습니다.
첫 번째는이 두 클래스에 통합 부모 클래스와 인터페이스가 없다는 것입니다 (XSSF 및 HSSF 옆집 옆집의 눈을 캐스팅합니다). 따라서 동일한 형식으로 인터페이스 프로그래밍을 수행 할 수 없습니다.
두 번째는 공식 API의 문서에서 그림의 상대적 위치에 대한 인터페이스가 없다는 것입니다. 이는 문서의 모든 그림을 얻을 수 있지만이 사진이 어디에 있는지 알 수 없다는 사실로 이어집니다. 앞으로는 올바른 위치에 그림을 삽입 할 수 없습니다.
첫 번째 시점에서는 Jacob, Doc4J 등과 같은 다른 관련 기술을 연구하여 다른 솔루션이 있는지 확인할 수는 없지만 Doc4J는 2007 문서 (.docx)를 처리 할 수있는 것 같습니다.
두 번째 시점 에서이 기사는 저에게 저자의 솔루션을 제공합니다. 사실, 이것은 또한이 기사를 쓰는 목적이기도합니다.
참고 : 단순히 속도를 요구하는 경우 2 장과 3 장을보십시오.
1. 준비 지식
1. Word 문서의 두 형식은 두 가지 다른 스토리지 방법에 해당합니다.
우리 모두 알다시피, Word 문서에는 Doc과 Docx의 두 가지 저장 형식이 있습니다.
DOC : 일반적으로 이진 저장 데이터를 사용하는 Word2003이라고합니다. 이것은 오늘날 우리의 토론의 초점이 아닙니다.
DOCX : Word2007은 XML을 사용하여 데이터 및 형식을 저장합니다.
어쩌면 당신은 왜 DOCX에서 끝나는 문서 인 XML 형식입니까?
매우 간단합니다. DOCX 파일을 선택하고 오른쪽 버튼을 클릭하여 압축 도구로 열면 다음과 같은 디렉토리 구조를 얻을 수 있습니다.
따라서 DOCX는 완전한 문서라고 생각하지만 실제로는 압축 파일 일뿐입니다. (docx :? _?)
2. Word 문서에서 XML의 정의 형식 :
이전 예에서 DOCX 문서는 압축 파일, 즉 XML을 사용하여 데이터를 설명한다는 것을 알게되었습니다. 그렇다면 Word 문서의 데이터는 구체적으로 어떻게 정의됩니까?
공간으로 인해 전체 압축 문서는 여기에 자세히 설명되지 않습니다. 나는 두 개의 파일/폴더를 간단히 소개합니다.
먼저, Word Directory의 document.xml 파일은 전체 문서 내용의 정의입니다.
두 번째는 단어 디렉토리의 미디어 폴더입니다. 이름을 보면 문서의 멀티미디어 컨텐츠를 추측 할 수 있습니다.
그림 3 : Word/Document.xml (문서 내용 정의)
그림 4 : 단어/미디어 폴더 아래의 내용
다음은 document.xml 문서의 몇 가지 주요 내용입니다.
A : 전체 구조 정의 문서 :
<W : 문서 MC : 무지 = "W14 W15 WP14"XMLNS : M = "http://schemas.openxmlformats.org/officedocument/2006/math"xmlns : mc = "http://schemas.openxmlformats.org/markupcatichiable/20066. XMLNS : O = "URN : SKEMAS-MICROSOFT-COM : OFFICE : OFFICE"XMLNS : r = "http://schemas.openxmlformats.org/officedocument/2006/relationships"xmlns : v = "urn : schemas-microsoft-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/office/word/2010/wordml" 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/wordprocessingdrawing" xmlns : wpg = "http://schemas.microsoft.com/office/word/2010/wordprocessingcanvas"xmlns : wpg = "http://schemas.microsoft.com/office/word/2010/wordprocessinggroup" 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 : val = "2"> </w : pStyle> <w : keepnext w : val = "0"> W : val = "0"> </w : keeplines> <w : widowcontrol> </w : widowcontrol> <w : val = "0"> </w : suppresslinenumbers> <w : pbdr> <w : 상단 W : "auto"w : space = "0 <w : sz ="0 "W : val"v val "v val"val "val"val "val"val "val"val "val"val "0"val "val"val "val"val "val"val "val"0 w : color = "auto"w : space = "0"w : val = "none"> </w : 맨 아래> <w : 오른쪽 w : color = "auto"w : space = "0"w : sz = "0"w : val = "none"> </w : right> </w : pbdr>
B : 문서 단락 내용 :
<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 : widowconol> </w : suppresslinenumbers> <w : pbdr> <w : 상단 w : color = "auto"w : space = "0"w : sz = "0"> </w : top> <w : "auto"w : space = "0"w : sz = "0"> w : val = "없음"> </w : left> <w : color = "w :"w : "w :"w : left> <w : sz = "0"w : sz = "0"> w : val = "none"> w : sz = "0"w : val = "none"> </w : 하단> <w : 오른쪽 w : color = "auto"w : space = "0"w : sz = "0"w : val = "none"> </w : right> </w : pbdr> <w : shd w : "fafafa"w : val = "clear"> </w : shd> W : AfterAutospacing = "0"W : 전 = "150"W : Beforeautospacing = "0"w : line = "378"W : Linerule = "Atleast"> </w : spacing> <w : ind w : indline = "0"w : left = "0"w : right = "0"> </w : ind> <w : rpr> w : cs = "verdana"w : hansi = "verdana"w : hint = "default"> </w : rfonts> <w : iw : val = "0"> </w : i> <w : val = "0"> </w : caps> <w : val = "404040"> </w : <w : spacing w : val = "> </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 : val = "404040"> </w : color> <w : val = "0 </w : spacing> 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 : shd w : shd w : </w : </w : : val = val = val = val "> </w : shd> </w : rpr> <w : t> 저자 : Brian Dear </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 : caps w : val = "0"> </w : <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 : bdr w : space "w :"0 w : : sz " W : val = "none"> </w : bdr> <w : shd w : fill = "fafafa"w : val = "clear"> </w : shd> </w : rpr> <w : inline distb = "0"distl = "114300"114300 "dist ="0 "0"distl = "0"0 "distl ="0 "0"0 "0"0 "<wp : extent cx ="5543550 cy = "5543550"> </wp : elpent> <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 : cnvgraphcamepr> <a : graphicframelocks nochangeaspect = "1"xmlns : a = "http://schemas.openxmlformats.org/drawingml/2006/main"> </a : graphicframelocks> </wp : cnvgraphicframepr> <a : 그래픽 xmlns : a = "http://schemas.openxmlformats.org/drawingml/2006/main"> <a : graphicdata uri = "http://schemas.openxmlformats.org/drawingml/2006/picture"> pic : pic xmlns : pic = "http://schemas.openxmlformats.org/drawingml/2006/picture"> <pic : nvpicpr> <pic : cnvpr descr = "img_256"id = "1"picture 1 "> </pic : cnvpr> <a : cnvpicpr> nochangeaspect = "1"> </a : piclocks> </pic : cnvpicpr> </pic : nvpicpr> <pic : blipfill> <a : blip r : embed = "rid4"> </a : blip> <a : rectort> <a : fillrect> </a : fillRect> </</</pic> </pic> : blipfill> </pfl> </</</</</a : <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 : prstgeom> <a : nofill> </a : nofill> <a : ln w = "9525"> <a : nofill> </a : nofill> </a : ln> </pic : sppr> </pic : pic> </a : graphicdata> </a : graphic> </wp : inline> </w : drawing> </w : r>
관심이 있으시면 위의 세 가지 XML 코드를 볼 수 있습니다. 나는 여기에 직접 결론을 내릴 것입니다.
Word Document Shema 파일 : xmlns : w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
루트 노드 문서 : <w : 문서> 전체 문서의 시작을 정의합니다.
<w : body>는 문서의 자식 노드이며 문서의 주요 내용입니다.
<w : p> 단락 인 Body Child Node는 Word 문서의 단락입니다.
<w : r> p 요소의 하위 노드, 런은 단락에서 동일한 형식의 단락을 정의합니다.
<w : t> 실행 요소 노드의 자식 노드는 문서의 내용입니다.
<W : 드로잉> 런 요소의 하위 노드, 그림을 정의합니다.
<W : 인라인> 어린이 노드 그리기, 특정 응용 프로그램에 대한 심층적 인 연구는 없었습니다.
<A : 그래픽> 이미지 내용 정의
<pic : blipfill> 이것은 이미지 컨텐츠의 인덱스를 정의하는 그래픽 문서의 자식 노드입니다. 구체적으로, POI는이 이름에 따라 이미지의 해당 리소스를 얻을 수 있으며 문서 이미지의 위치를 얻는 열쇠는 여기에 있습니다.
전반적으로 XWPF DOCX 문서를 구문 분석하는 것은 XML 문서를 구문 분석하고 모든 노드를 저장 한 다음보다 유용한 특성으로 변환하여 사용자가 사용할 API를 제공하는 것입니다.
따라서 POI가 제공 한 인터페이스를 사용하여 문서 컨텐츠를 가져오고 문서의 데이터를 직접 구문 분석하고 사진이 어떤 단락을 얻을 수 있습니다. 물론, 사진이 뒤에 있는지 알 수 있습니다.
2. 실현
package com.szdfhx.reportstatistic.util; import com.microsoft.schemas.vml.ctshape; import org.apache.poi.xwpf.usermodel.xwpfparagraph; import org.apache.poi.xwpf.usermodel.xwpfpppficturedata; org.apache.poi.xwpf.usermodel.xwpfrun; import org.apache.xmlbeans.xmlcursor; import org.apache.xmlbeans.xmlobject; import org.openxmlformats.schemas.drawingml.x2006.main.ctgraphicalob importobcialobject; org.openxmlformats.schemas.schemas.x2006.picture.ctpicture; import org.openxmlformats.schemas.drawingml.x2006.main.ctdrawing; import org.openxmlformats.schemas.wordprocessingml.x2006.main.ctob; 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 {// 모든 이미지 지수를 얻으십시오. readImageInparagraph (XWPFPARAGRAPH PARGRAPH) {// 이미지 색인 목록 <String> imageBundLelist = new ArrayList <string> (); // 모든 xwpfrun 목록 <xwpfrun> 단락 런리스트 = 문단 .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 (); // child 요소가 <w : drawing>의 형태 인 경우 ctrawing을 사용하여 이미지를 저장합니다. (o 인스턴스 Ctdrawing) {ctdrawing drawing = (ctdrawing) o; ctinline [] ctinlines = drawing.getinlinearray (); for (ctinline ctinline : ctinlines) {ctgraphicalobject 그래픽 = ctinline.getgraphic (); // xmlCursor Cursor = Graphic.getGraphicData (). newCursor (); cursor.selectpath ( "./*"); while (cursor.tonextSelection ()) {xmlobject xmlobject = cursor.getObject (); // child 요소가 <pic : pic> if (xmlobject instance의 ctpicture) 형식 인 경우 {org.openxmlformats.schemas.drawingml.x2006.picture.ctpicture picture = (org.openxmlformats.schemas.drawingml.x2006.picture.ctpicture) xmlobicture; // 요소의 속성을 가져옵니다. ImageBundLelist.add (picture.getBlipFill (). getBlip (). getEmbed ()); }}}}} // ctobject를 사용하여 이미지를 저장하십시오 // <w : object> form if (o instanceof ctobject) {ctobject object = (ctobject) o; System.out.println (객체); xmlcursor w = object.newcursor (); w.selectpath ( "./*"); while (w.tonextSelection ()) {xmlobject xmlobject = w.getObject (); if (xmlobject instanceof ctshape) {ctshape shape = (ctshape) xmlobject; ImageBundLelist.add (shape.getImageDataArray () [0] .getId2 ()); }}}}} return ImageBundLelist; }}우선, XWPF에 의해 XML 요소의 캡슐화를 제안해야합니다.
<w : 문서> XWPFDocument 클래스에 해당합니다
<w : run> xwpfrun 클래스에 해당합니다
기본적으로 런 레이어에만 해당합니다. 실행의 어린이 요소가 많기 때문에 더 이상 다음 수준에서 캡슐화와 정의가 없습니다.
따라서 모든 XWPFrun 객체 만 XML 정의로 변환 할 수 있습니다 : CTR 객체. 마지막으로 CTR을 사용하여 실행 요소의 내용을 읽고 구문 분석하고 이미지의 색인을 얻으십시오.
두 번째로 이야기해야 할 것은 전체 XML 요소의 정의입니다.
우리는 POI가 Apache의 XMLBeans 기술에 의해 구문 분석 된 XML을 사용한다는 것을 알 수 있습니다. 관련 기술에 대해 깊이 논의하지 않으면 두 가지 핵심 사항을 이해해야합니다.
1 : XML 문서의 모든 요소는 XMLBEAN에 의해 캡슐화되고 XMLobject 인터페이스를 상속 받으 므로이 클래스를 사용하여 획득 한 자식 요소를 수신 할 수 있습니다.
2 : 요소 트래버스는 XMLCursor를 통해 수행됩니다. 자식 요소의 특정 획득은 XMLCursor 객체의 SelectPath 속성에 따라 제어됩니다. SelectPath가 "./*"인 경우, 이는 아동 요소를 가로 지르는 것으로 정의됩니다.
따라서 다음과 같이 작성됩니다. 현재 요소의 자식 요소를 가로 지르고 자식 요소의 유형을 확인할 수 있습니다.
ctr ctr = run.getctr (); // 어린이 요소 전환 xmlcursor c = ctr.newcursor (); // 이것은 모든 자식 요소를 얻는 것입니다 : c.selectpath ( "./*"); while (c.tonextSelection ()) {xmlobject o = c.getObject (); // child 요소가 <w : drawing> 형식 인 경우 ctrawing을 사용하여 그림을 저장하기 위해 (ctdrawing) {ctdrawing drawing = (ctdrawing) o;마지막으로, 당신은 질문이있을 수 있습니다.이 요소 <w : drawing>은 이미지를 정의하지 않았습니까?
그래서
if (o 인스턴스의 ctobject) {ctobject object = (ctobject) o; ...}두 번째 판단 조건은 무엇입니까?
당신은 그것을 추측했을 것입니다
좋아요! <w : drawing> 외에도 DOCX 문서의 XML을 사용하여 이미지를 정의 할 수 있습니다.
왜이 두 가지만 있습니까?
첫 번째 방법을 구문 분석하는 방법 만 사용했기 때문에 일부 사진이 손실 된 것을 알았으므로 두 번째 방법을 찾았습니다 ... 어쩌면 두 개 이상이 있습니까? 어쨌든 지금은 나에게 아무런 문제가 없다는 것을 모른다.
아마도 당신은 똑똑한 사람이 실제로 더 많은 상황을 만났을까요?
그런 다음 위에서 언급 한 XML 구문 분석 방법을 사용하면 올바르게 읽고 원하는 인덱스 값을 얻을 수 있다고 생각합니다.
조금 넓 힙니다. POI가 제공하지 않은 다른 API가있는 경우 XML 구문 분석 기술을 통해이를 구현할 수 있습니까? 이것은 우리가 실제로 탐구해야합니다. 나는 시간이 우리에게 답을 줄 것이라고 믿는다.
좋아, 이제 우리는 인덱스 값을 얻었으므로 이미지 자원을 얻을 수있는 방법은 무엇입니까?
POI는 기성품 방법을 제공합니다.
xwpfdocument 클래스에는 getPicturedatatabyid (문자열 사진)가 있습니다.
이 방법은 이미지 자원 인 XWPFPictruedate 객체를 얻을 수 있습니다.
특정 작업은 관련 블로그 게시물과 API를 참조하십시오. 여기에는 자세히 소개되지 않습니다.
3. 테스트 :
Junit4를 사용하여 테스트 할 코드 :
패키지 com.szdfhx.reportStatistic.util; import org.apache.commons.collections.collectionUtils; import org.apache.commons.lang.stringutils; import org.apache.poi.xwpff.usermodel.xwpdocument; 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.ioexception; java.io.inputstream; java.util.collections; import java.util.list; import static org.junit.assert.*; public class xwpfutilstest {@test public void void readimageinparagraph () Ioexception {inputStream in new fileInputStream ( "d : // my blog // java parsing Word in get word in document // example.docx "); xwpfdocument xwpfdocument = new xwpfdocument (in); list <xwpfparagraph> paragraphlist = xwpfdocument.getparagraphs (); System.out.println ( "이미지 색인/t | 이미지 이름/t | 이미지/t에서 텍스트 단락의 내용"); System.out.pringln("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ if (collectionUtils.isnotempty (ImageBundLelist)) {(string pictureId : imageBundLelist) {xwpfpicturedata = xwpfdocument.getPicturedAbyId (pictureId) imageName = picturetata.getParaphte (getParaphte); system.out.println (pictureId + "/t |" + imageName + "/t |" + lastParAgraphText);결과 표시 :
여기에 이미지 이름을 사용한다는 것은 해당 리소스를 얻었음을 의미합니다. 실제로 이전 기사의 내용에 익숙하다면 이미지의 이름이 실제로 Word/Media 폴더의 모든 이미지의 전체 이름임을 알게됩니다.
해당 xwpfpicturedata 객체에서 이미지의 이진 데이터는 getData () 속성을 통해 얻을 수 있으므로 데이터베이스 또는 로컬 폴더에 저장할 수 있습니다!
4. 기타 :
이것에 대해 말하면, 처음에 언급 된 두 번째 문제는 여기에서 해결되었습니다.
그렇다면 첫 번째 질문으로 무엇을해야합니까?
시스템이 고속이 필요하지 않은 경우 DOC 문서를 DOCX 문서로 변환하는 것이 제 조언입니다. POI에는 성숙한 API가 있습니다.
성능을 고려하려면 문서를 구문 분석하려면 두 가지 방법 세트를 작성해야합니다.
그렇다면 ... DOC-TYPE Word 문서에서 이미지의 상대적 위치를 얻는 방법은 무엇입니까?
모르겠어 ... 아니면 와서 말해?
위의 Java Parsing Word에서 문서에서 그림의 위치를 얻는 방법은 내가 공유하는 모든 내용입니다. 나는 당신이 당신에게 참조를 줄 수 있기를 바랍니다. 그리고 당신이 wulin.com을 더 지원할 수 있기를 바랍니다.