Prefácio (Introdução em segundo plano):
O Apache POI é o próximo projeto de código aberto da Apache Foundation, usado para processar documentos na série Office e pode criar e analisar documentos nos formatos Word, Excel e PPT.
Existem duas tecnologias para o processamento de documentos do Word, a saber, HWPF (.doc) e XWPF (.docx). Se você estiver familiarizado com essas duas tecnologias, poderá entender a dor de usar o Java para analisar documentos do Word.
Dois dos maiores problemas são:
A primeira é que essas duas classes não têm uma classe pai e interface unificadas (XSSF e HSSF ao lado lançam seus olhos desprezíveis), para que não possam executar a programação da interface no mesmo formato;
A segunda é que não há interface para a posição relativa das imagens no documento na API oficial, o que leva ao fato de que, embora você possa obter todas as imagens no documento, não pode saber onde estão essas imagens. No futuro, você não poderá inserir as imagens na posição correta.
Pelo primeiro ponto, não tenho escolha a não ser estudar outras tecnologias relacionadas, como Jacob, Doc4j, etc., para ver se existem outras soluções, mas o DOC4J parece ser capaz de processar documentos de 2007 (.docx).
Para o segundo ponto, este artigo me dará a solução do autor. De fato, esse também é o objetivo de escrever este artigo.
NOTA: Basta olhar para o capítulo 2 e o capítulo 3 se você está simplesmente pedindo velocidade;
1. Conhecimento de preparação
1. Os dois formatos de documentos do Word correspondem a dois métodos de armazenamento diferentes
Como todos sabemos, os documentos do Word têm dois formatos de armazenamento: DOC e DOCX
DOC: é comumente chamado Word2003, que usa dados de armazenamento binário ; Este não é o foco de nossa discussão hoje.
DOCX: Word2007, usa XML para armazenar dados e formato.
Talvez você pergunte, por que é um formato XML que é obviamente um documento que termina no DOCX?
É muito simples: você pode apenas selecionar um arquivo DOCX, clique com o botão direito do mouse para abri-lo com a ferramenta de compactação e obter uma estrutura de diretório como esta:
Então você acha que o DOCX é um documento completo, mas na verdade é apenas um arquivo compactado. (Docx :? _?)
2. O formato de definição de XML nos documentos do Word:
No exemplo anterior, aprendemos que os documentos do DOCX usam arquivos compactados, ou seja, XML para descrever os dados. Então, como os dados nos documentos do Word são definidos especificamente?
Devido ao espaço, todo o documento compactado não será descrito em detalhes aqui. Vou apresentar brevemente dois arquivos/pastas:
Primeiro, o arquivo document.xml no diretório do Word, que é a definição de todo o conteúdo do documento;
O segundo é a pasta de mídia no diretório da palavra. Você pode adivinhar o conteúdo multimídia no documento, olhando para o nome:
Figura 3: Word/Document.xml (Defina o conteúdo do documento)
Figura 4: Conteúdo sob a pasta Word/Media
A seguir, são apresentados alguns conteúdos importantes do documento.xml Document:
R: Definição de estrutura geral do documento:
<w:document mc:ignorable="w14 w15 wp14" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns: o = "urn: schemas-microsoft-com: Office: Office" xmlns: r = "http://schemas.openxmlformats.org/officedocument/2006/relationships" xmlns: v = "urn: schema-mactossofsofships: xmlns: v =" urn: schema-mactossofsofships: xmlns: v = "urn: schema-mactossofsofts: xmlns: v =" urn: schema-mactossofsofships: xmlns: v = "urn: schema-macossoflosflships. xmlns: w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns: w10 = "urn: schemas-microsoft-com: Office: word" xmlns: w14 = "htttp://schem xmlns: w15 = "http://schemas.microsoft.com/office/word/2012/wordml" xmlns: wne = "http://schemas.microsoft.com/office/word/word/word/wordml" xmlns: wp = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns: wp14 = "http://schemas.microsoft.com/fford/word/20/20/20/20/20/20/20/2010/2014/" xmlns: wpg = "http://schemas.microsoft.com/office/word/2010/wordprocessingcanvas" xmlns: wpg = "http://schemas.microsoft.com/office/word/2010/2010/2010/socessingGroup" xmlns: wpi = "http://schemas.microsoft.com/office/word/2010/wordProcessingink" xmlns: wps = "http://schema.microsoft.com/office/word/word/word/wordpprocessingshape" xmlns: wpScustomdata = "http://www.wps.cn/officedocument/2013/wpscustomdata"> <w: body> <w: p> <w: ppr> <w: pstyle w: val = "2"> </w: pstyle> <w. <w: keeplines w: val = "0"> </w: keeplines> <w: widowcontrol> </w: widowcontrol> <w: suprimeNeNumbers w: val = "0"> </w: suprimlinenumbers> <w: pbdr> <w: top: color = "" auto "w: space:" W: "w: space" 0 "weresslinenumbers> <w: pbdr> <s: top:" "" "0" w: space: "WeressLeNEnNums> </w: top> <w: esquerda w: color = "auto" w: space = "0" w: val = "nenhum"> </w: bottom> <w: direita w: color = "auto" w: space = "0" w: sz = "0" w: val = "nenhum"> </w: direita> </w: pbdr>
B: Conteúdo do parágrafo do documento:
<w: p> <w: ppr> <w: pstyle w: val = "2"> </w: pstyle> <w: ketNext w: val = "0"> </w: keepNext> <w: Keeplines w: val = "0"> </w: keeplines> <w: widowControl> </w: supressiveNenumbers> <w: pbdr> <w: topo w: color = "auto" w: space = "0" w: sz = "0"> </w: top> <w: esquerda w: color = "Auto" W: Space = "0" W: Sz = "0">: Val = "ENO"> </w: W: "0" 0 "W: Sz =" 0 ">: Val =" ""> </w: W: "" w: sz = "0" w: val = "none"> </w: inferior> <w: direita w: color = "auto" w: space = "0" w: sz = "0" w: val = "nenhum"> </w: right> </w: pbdr> <w: shd: preenchimento = "fafafa" w: n: w: w: w: w: pbdr> <w: shd: preenchimento = "fafafa" w: n: w: w: w: w: pbdr> <w: Shd: Fill = "fafafa" W: Val ":" W: Afterautospacing = "0" W: Antes = "150" W: BeforeAutospacing = "0" W: Line = "378" W: linerule = "pelotleast"> </w: Spacacing> <w: Ind W: FirstLine = "0" W: Left = "0" W: Direito = "0"> </w: ind> w: cs = "verdana" w: hansi = "verdana" w: hint = "default"> </w: rfonts> <w: iw: val = "0"> </w: i> <w: caps w: val = "0"> </s: caps> <w: cor: val = "404040" </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: cor w: val = "404040"> 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 = "nenhum"> </w: bdr> <w: shd w: "0" w: ffaf </w: rpr> <w: t> Autor: Brian querido </w: t> </w: r> </w: p>
C: Definição de conteúdo da imagem:
<w: r> <w: rpr> <w: rfonts w: ascii = "verdana" w: cs = "verdana" w: hansi = "verdana" w: hint = "default"> </w: rfonts> <w: iw: val = "0"> </: i> <w: caps w: val " w: val = "404040"> </w: cor> <w: espaçamento w: val = "0"> </w: espaçamento> <w: sz w: val = "21"> </w: sz> <w: szcs w: val = "21"> </w: szcs> <w: szcs "" "21"> w: val = "nenhum"> </w: bdr> <w: shd w: preench = "fafafa" w: val = "clear"> </w: shd> </w: rpr> <w: desenho> <wp: inline distb = "0" distl = "114300" dist = "114300" dist = "0"> cy = "5543550"> </wp: extensão> <wp: efetextent b = "0" l = "0" r = "0" t = "0"> </wp: efetExtent> <wp: docpr descr = "img_256" id = "1" name = "1"> </wp: docpr> Nochangeaspect = "1" xmlns: a = "http://schemas.openxmlformats.org/drawingml/2006/main"> </a: graphicframelocks> </wp: cnvgraphicframepr> <a: graphicics> xmlns: a = "http://schemas.openxmlformats.org/drawingml/2006/main"> <a: graphicdata uri = "http://schemas.openxmlats.org/drawingml/2006/PTICT" 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:stretch> </pic:blipfill> <pic:sppr> <a:xfrm> <a: off x = "0" y = "0"> </a: off> <a: ext cx = "5543550" cy = "5543550"> </a: ext> </a: xfrm> <a: prStgeom prst = "rect"> </AvlSt </a: AVLST> </a: p. <a: ln w = "9525"> <a: nofill> </a: nofill> </a: ln> </pic: sppr> </pic: pic> </a: graphicdata> </a: graphic> </wp: inline> </w: drawer> </w: r>
Se você estiver interessado, pode olhar para os três códigos XML acima. Vou dar a conclusão diretamente aqui:
Documento do Word Arquivo Shema: xmlns: w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
Nó raiz do documento: <w: document> define o início de todo o documento
<w: body> é o nó infantil do documento e o conteúdo principal do documento
<w: p> Nó da criança corporal, um parágrafo, é o parágrafo no documento do Word
<w: r> nó filho do elemento P, uma corrida define um parágrafo com o mesmo formato no parágrafo
<w: t> O nó filho do nó do elemento de execução é o conteúdo do documento.
<w: desenho> nó filho do elemento de execução, define uma imagem:
<w: inline> Desenho de nós filhos, nenhuma pesquisa aprofundada foi feita sobre a aplicação específica.
<a: gráfico> Defina o conteúdo da imagem
<Pic: Blipfill> Este é um nó filho do documento gráfico, que define o índice do conteúdo da imagem. Especificamente, o POI pode obter os recursos correspondentes da imagem com base nesse nome e a chave para obter a localização da imagem do documento está aqui.
No geral, o XWPF analisando documentos DOCX é analisar o documento XML, salvar todos os nós e convertê -los em propriedades mais úteis, fornecendo API para os usuários usarem.
Portanto, podemos usar a interface fornecida a nós pela POI para obter o conteúdo do documento, analisar os dados no documento e obter em qual parágrafo a imagem está. É claro que você também pode saber em qual elemento executar a imagem está localizada atrás.
2. Realização
pacote com.szdfhx.reportStatistic.util; importar com.microsoft.schemas.vml.ctshape; importar org.apache.poi.xwpf.usermodel.xwpfparagraph; import org.apache.poi.xwpf.sermodel.xwpict; org.apache.poi.xwpf.usermodel.xwpfrun; importar org.apache.xmlbeans.xmlcursor; importar org.apache.xmlbeans.xmlobject; importação org.openxmlformats.schema.brawingml.x2006.minin.main.Main.Main.Cformats.schemas.brawingml.x2006.Main.Main.Main.Main.Main.Cormats.SchemaphingMelical.x2006.main.Main.Main.Main. org.openxmlformats.schemas.drawingml.x2006.picture.ctpicture; importar org.openxmlformats.schemas.drawingml.x2006.main.ctdrawing; import.port.openxmlformats.schemas.MainPrAwing; import.mport.openxmut.mChemas.MainPrdrwing; import.openxmut.mChemas.MainPrdrwing; org.openxmlformats.schemas.wordprocessingml.x2006.main.ctr; importar java.util.arraylist; importar java.util.list; importar java.util.list; importar java.util.map em classes públicas xwpfutils {/gget fetting fets fatt). ReadImageInparagraph (parágrafo xwpfParagraph) {// Lista de índice de imagem <String> imageBundLelist = new ArrayList <String> (); // Toda a lista XWPFRUN <XWPFRUN> no parágrafo runlist = paragraph.getRuns (); para (xwpfrun run: runlist) {// xwpfrun é seu próprio atributo gerado pelo POI depois de analisar o elemento XML. Não pode ser analisado através do XML. Ele precisa ser convertido em ctr ctr = run.getCtr (); // transação de elementos filho xmlcursor c = ctr.newcursor (); // Isso é para obter todos os elementos filhos: C.SelectPath ("./*"); while (c.TonextSelection ()) {xmlObject o = c.getObject (); // Se o elemento filho estiver na forma de <w: desenho>, use o CTDRAWING para salvar a imagem se (o Instância de Ctdrawing) {CtDrawing Drawing = (ctDrawing) o; Ctinline [] ctinlines = drawer.getInlinearray (); for (ctinline ctinline: ctinlines) {ctgraphicalObject graphic = ctinline.getgraphic (); // xmlcursor cursor = graphic.getgraphicData (). NewCursor (); cursor.SelectPath ("./*"); while (cursor.tonextSelection ()) {xmlobject xmlobject = cursor.getObject (); // se o elemento filho está no formulário <pic: pic> if (xmlObject Instância de ctpicture) {org.openxmlformats.schemas.drawingml.x2006.picture.ctpicture picture = (org.openxmlformats.schemast.drawingml.xlesture; // Obtenha o atributo do elemento ImageBundLelist.add (Picture.getBlipfill (). GetBlip (). Getembed ()); }}}}} // use ctobject para salvar a imagem // <w: object> form se (o instância de ctobject) {ctobject Object = (ctobject) o; System.out.println (objeto); Xmlcursor w = object.NewCursor (); w.SelectPath ("./*"); while (w.tonextSelection ()) {xmlObject xmlobject = w.getObject (); if (xmlObject Instância de ctshape) {forma ctShape = (ctshape) xmlobject; ImageBundLelist.add (shap.getImagedataArray () [0] .getId2 ()); }}}}} retornar ImageBundLelist; }}Primeiro de tudo, precisamos propor o encapsulamento de elementos XML por XWPF:
<W: Document> correspondente à classe XWPFDocument
<w: run> correspondente à classe XWPFRUN
Basicamente, isso corresponde apenas à camada de execução. Como existem muitos elementos infantis de corrida, não há mais encapsulamento e definição no seguinte nível.
Portanto, só podemos obter todos os objetos xwpfrun convertidos em sua definição XML: objetos CTR. Por fim, use o CTR para ler e analisar o conteúdo do elemento de execução e obtenha o índice da imagem.
A segunda coisa a falar é a definição de todo o elemento XML:
Podemos ver que o POI usa XML analisado pela tecnologia XMLBeans no Apache. Se você não discutir as tecnologias relacionadas em profundidade, deve entender dois pontos -chave:
1: Todos os elementos no documento XML são encapsulados pelo XMLBean e herdam uma interface xmlobject, para que essa classe possa ser usada para receber os elementos filho adquiridos;
2: O elemento Traversal é feito através do XMLCursor. A aquisição específica de elementos filhos é controlada com base no atributo selectPath do objeto XMLCursor. Quando o seleto é "./*", é definido como atravessando elementos filhos;
Portanto, está escrito da seguinte forma: pode atravessar os elementos filhos do elemento atual e verificar o tipo do elemento filho:
Ctr ctr = run.getctr (); // transau os elementos filho xmlcursor c = ctr.newcursor (); // Isso é obter todos os elementos filho: c.selectPath ("./*"); while (c.TonextSelection ()) {xmlObject o = c.getObject (); // Se o elemento filho estiver no formulário <w: desenhando>, use ctdrawing para salvar a imagem se (o instância de ctdrawing) {ctDrawing desenhando = (ctrawing) o;Finalmente, você pode ter dúvidas, esse elemento <w: desenho> definiu uma imagem?
Então
if (o Instância de ctobject) {objeto ctobject = (ctobject) o; ...}Para qual é a segunda condição de julgamento usada?
Você deveria ter adivinhado
Isso mesmo! Além de <W: Desenho>, o XML no documento DOCX também pode ser usado para definir a imagem.
Por que existem apenas esses dois?
Como eu só usei o primeiro método para analisar, descobri que algumas fotos foram perdidas, então encontrei o segundo método ... talvez haja mais de dois? De qualquer forma, não sei, não há problema para mim no momento.
Talvez você, que seja inteligente, tenha encontrado mais situações na prática?
Em seguida, usando o método de análise XML mencionado acima, acredito que você pode lê -lo corretamente e obter o valor do índice que deseja.
Amplie um pouco. Se houver outras APIs que não são fornecidas pelo POI, também podemos implementá -las através da tecnologia XML Parsing? Isso exige que exploremos na prática. Eu acredito que o tempo nos dará a resposta.
Ok, agora temos o valor do índice, então como obtemos os recursos da imagem?
O POI fornece métodos prontos:
Há getPictUredAtabyId (imagem da string) na classe XWPFDocument;
O método pode obter o objeto xwpfpictruedate, que é o recurso de imagem.
Para operações específicas, consulte as postagens e APIs relevantes do blog, que não serão introduzidas em detalhes aqui.
3. Teste:
Código para testar usando o Junit4:
pacote com.szdfhx.reportStatistic.util; importar org.apache.commons.collections.collectionutils; importar org.apache.commons.lang.stringutils; importar org.apache.poi.xwpf.usermodel.xwpfdocument; org.apache.poi.xwpf.usermodel.xwpfparagraph; importar org.apache.poi.xwpf.usermodel.xwpfpictureData; importação org.junit.test; importe java.io.fileaRanstram; java.util.Collections; importar java.util.list; importar org.junit.assert. document // exemplo.docx "); Xwpfdocument xwpfdocument = novo xwpfdocument (in); Lista <XWPFParagraph> paragraphlist = xwpfdocument.getParagraphs (); System.out.println ("INDEX INDECE/T | Nome da imagem/T | Conteúdo de um parágrafo de texto na imagem/t"); System.out.pringln("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ if (collectionutils.isnotempty (imagebundlelist)) {for (string pictureId: imagebundlelist) {xwpfPictureData PictureData = xwpfdocument.getPictureDatabyId (stringId); paragraphlist.get (i-1) .getParagraphText ();Mostrar resultados:
O uso de nomes de imagens aqui significa que obtive os recursos correspondentes. De fato, se você estiver familiarizado com o conteúdo do artigo anterior, descobrirá que o nome da imagem é realmente o nome completo de todas as imagens na pasta Word/Media.
No objeto XWPFPictureData correspondente, os dados binários da imagem podem ser obtidos através da propriedade getData (), para que você possa salvá -lo no banco de dados ou na sua pasta local!
4. Outros:
Falando nisso, o segundo problema mencionado no início foi resolvido aqui.
Então, o que devo fazer com a primeira pergunta?
Se o seu sistema não exigir alta velocidade, meu conselho é converter o documento do documento em documento DOCX para analisar - POI tem uma API madura para fazer
Se você deseja considerar o desempenho, deve escrever dois conjuntos de métodos para analisar o documento.
Então ... como obter a posição relativa da imagem em um documento do Word do tipo Doc?
Eu não sei ... ou venha me dizer?
Na palavra de análise Java acima, o método para obter a localização da imagem no documento é todo o conteúdo que compartilho com você. Espero que você possa lhe dar uma referência e espero que você possa apoiar mais o wulin.com.