Prefacio (introducción de fondo):
Apache POI es el próximo proyecto de código abierto de la Fundación Apache, utilizado para procesar documentos en la serie de oficina y puede crear y analizar documentos en formatos de Word, Excel y PPT.
Hay dos tecnologías para procesar documentos de Word, a saber, HWPF (.doc) y XWPF (.docx). Si está familiarizado con estas dos tecnologías, debería poder comprender el dolor de usar Java para analizar los documentos de Word.
Dos de los mayores problemas son:
La primera es que estas dos clases no tienen una clase e interfaz principal unificada (XSSF y HSSF de al lado arrojan sus ojos despectivos), por lo que no pueden realizar la programación de interfaz en el mismo formato;
El segundo es que no hay interfaz para la posición relativa de las imágenes en el documento en la API oficial, lo que lleva al hecho de que, aunque puede obtener todas las imágenes en el documento, no puede saber dónde están estas imágenes. En el futuro, no podrá insertar las imágenes en la posición correcta.
Para el primer punto, no tengo más remedio que estudiar otras tecnologías relacionadas, como Jacob, Doc4j, etc., para ver si hay otras soluciones, pero DOC4J parece ser capaz de procesar documentos de 2007 (.docx).
Para el segundo punto, este artículo me dará la solución del autor. De hecho, este también es el propósito de escribir este artículo.
Nota: solo mire el Capítulo 2 y el Capítulo 3 si simplemente está pidiendo velocidad;
1. Conocimiento de preparación
1. Los dos formatos de documentos de Word corresponden a dos métodos de almacenamiento diferentes
Como todos sabemos, los documentos de Word tienen dos formatos de almacenamiento: DOC y DOCX
DOC: Se llama comúnmente Word2003, que utiliza datos de almacenamiento binario ; Este no es el foco de nuestra discusión hoy.
DOCX: Word2007, utiliza XML para almacenar datos y formatear.
Tal vez pregunte, ¿por qué es un formato XML que obviamente es un documento que termina en Docx?
Es muy simple: puede seleccionar un archivo Docx, hacer clic con el botón derecho para abrirlo con la herramienta de compresión y puede obtener una estructura de directorio como esta:
Entonces, cree que DOCX es un documento completo, pero de hecho es solo un archivo comprimido. (docx :? _?)
2. El formato de definición de XML en documentos de Word:
Del ejemplo anterior, aprendimos que los documentos DOCX usan archivos comprimidos, es decir, XML para describir los datos. Entonces, ¿cómo se definen específicamente los datos en los documentos de Word?
Debido al espacio, todo el documento comprimido no se describirá en detalle aquí. Solo introduciré brevemente dos archivos/carpetas:
Primero, el archivo document.xml en el directorio de Word, que es la definición de todo el contenido del documento;
El segundo es la carpeta de medios en el directorio de palabras. Puede adivinar el contenido multimedia en el documento mirando el nombre:
Figura 3: word/document.xml (Definir contenido del documento)
Figura 4: Contenido en la carpeta Word/Media
Los siguientes son algunos contenidos clave del documento Document.xml:
A: Documento de definición de estructura general:
<w: documento mc: ignorable = "w14 w15 wp14" xmlns: m = "http://schemas.openxmlformats.org/officeCedocument/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: Schemas-Microsoft-com: VML" xmlns: w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns: w10 = "urn: schemas-microsoft-com: oficina: word" xmlns: w14 = "http://schemas.microsoft.com/office/worth" 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/wordprocessingddrawing" 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: pstyle w: val = "2"> </w: pstyle> <w: keepnext w: val = "0" </w: w: val = "0"> </w: KeenLines> <w: widowcontrol> </w: widowcontrol> <w: supresslinenumbers w: val = "0"> </w: supresslineNumbers> <w: pbdr> <w: top w: color = "autó W: color = "Auto" W: Space = "0" W: Val = "Ninguno"> </W: Bottom> <W: Right W: Color = "Auto" W: Space = "0" W: Sz = "0" W: Val = "Ninguno"> </W: Right> </W: Pbdr>
B: Contenido de párrafo de documento:
<w: p> <w: ppr> <w: pstyle w: val = "2"> </w: pstyle> <w: keepNext w: val = "0"> </w: keepNext> <w: keeplines w: val = "0"> </w: Keenlines> <w: widowcontrol> </w: viudaControl> <w: supressresslinumbers w: val = "0" 0 "0" 0 " </w: supresslinenumbers> <w: pbdr> <w: top w: color = "auto" w: space = "0" w: sz = "0"> </w: top> <w: izquierda w: color = "auto" w: space = "0" w: sz = "0"> w: val = "none"> </w: izquierda> <w: bottom w: color = "auto" w: space "w w: space" 0 "0" 0 " w: sz = "0" w: val = "none"> </w: fondo> <w: derecho w: color = "auto" w: space = "0" w: sz = "0" w: val = "none"> </w: derecho> </w: pbdr> <w: shd w: relleno = "fafafa" w: val = "claro"> </w: shd> <w: spacing w: "150" W: AfterAutospacing = "0" w: antes = "150" W: beforeAteTospacing = "0" w: line = "378" W: Linerule = "AtlEast"> </W: Spacing> <w: ind w: fRIELLINE = "0" W: Left = "0" W: Right = "0"> </w: ind> <w: rpr> <w: rfonts w: w: "w:" verdana " w: cs = "verdana" w: hansi = "verdana" w: hintin = "predeterminado"> </w: rfonts> <w: iw: val = "0"> </w: i> <w: caps w: val = "0"> </w: caps> <w: color w: val = "404040"> </w: color> <w: vheping w: val = "0" 0 "0" 0 " </w: espaciado> <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" verdana " w: hansi = "verdana" w: hintin = "predeterminado"> </w: rfonts> <w: iw: val = "0"> </w: i> <w: caps w: val = "0"> </w: caps> <w: color w: val = "404040"> </w: color> <w: espaciado 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: relleno = "fafafa" </w: rpr> <W: t> Autor: Brian Dear </W: T> </W: R> </W: P>
C: Definición de contenido de imagen:
<w: r> <w: rpr> <w: rfonts w: ascii = "verdana" w: cs = "verdana" w: hansi = "verdana" w: hint = "predeterminado"> </w: rfonts> <w: iw: val = "0"> </w: i> <w: caps w: val = "0"> </w: caps> <w: color w: val = "404040"> </w: color> <w: espaciado w: val = "0"> </w: espaciado> <w: sz w: val = "21"> </w: sz> <w: szcs w: val = "21"> </w: szcs> <w: bdr w: color = "w: space =" 0 "w: sz =" 0 "0" 0 "0" W: val = "Ninguno"> </W: Bdr> <w: shd w: relleno = "fafafa" w: val = "clear"> </w: shd> </w: rpr> <w: dibujo> <wp: inline distb = "0" distl = "114300" Dist = "114300" Dist = "0"> <wp: extensor Cx = "5543550" cy = "5543550"> </wp: extens> <wp: effectExtent b = "0" l = "0" r = "0" t = "0"> </wp: effectExtent> <wp: docpr descr = "img_256" id = "1" nombre = "imagen 1"> </wp: doctor> <wp: cnvgraphicFramepr> <a: gtramEn NOCHANGEASPECT = "1" XMLNS: a = "http://schemas.openxmlformats.org/drawingml/2006/main"> </a: gráficoframelocks> </wp: cnvgraphicframepr> <A: Graphic xmlns: a = "http://schemas.openxmlformats.org/drawingml/2006/main"> <a: graphicData uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" xmlns: pic = "http://schemas.openxmlformats.org/drawingml/2006/picture"> <pic: nvpicpr> <pic: cnvpr descr = "img_256" id = "1" nombre = "imagen 1"> </pic: cnvpr> <pic: cnvpicpr> <A: piclocks nochangeAspect = "1"> </a: piclocks> </pic: cnvpicpr> </pic: nvpicpr> <pic: blipfill> <a: blip r: increm = "rid4"> </a: blip> <a: estirarse> <a: rellectect> <a: off x = "0" 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> </nofill <a: ln w = "9525"> <a: nofill> </a: nofill> </a: ln> </pic: spPr> </pic: pic> </a: graphicdata> </a: grafic> </wp: inline> </w: dibujo> </w: r>
Si está interesado, puede mirar los tres códigos XML anteriores. Daré la conclusión directamente aquí:
Word Document Shema File: xmlns: w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
Nodo de raíz del documento: <W: Documento> Define el comienzo de todo el documento
<w: body> es el nodo infantil del documento y el contenido principal del documento
<W: P> Body Child Node, un párrafo, es el párrafo en el documento de la palabra
<w: r> nodo infantil del elemento P, una ejecución define un párrafo con el mismo formato en el párrafo
<w: t> El nodo infantil del nodo del elemento ejecutivo es el contenido del documento.
<w: dibujo> nodo infantil del elemento ejecutivo, define una imagen:
<W: Inline> Dibujo de nodos infantiles, no se han realizado investigaciones en profundidad en la aplicación específica.
<A: Graphic> Definir contenido de imagen
<Pic: Blipfill> Este es un nodo infantil del documento gráfico, que define el índice del contenido de la imagen. Específicamente, POI puede obtener los recursos correspondientes de la imagen en función de este nombre, y la clave para obtener la ubicación de la imagen del documento está aquí.
En general, los documentos DOCX de análisis XWPF es analizar el documento XML, guardar todos los nodos y luego convertirlos en propiedades más útiles, proporcionando API para que los usuarios los usen.
Por lo tanto, podemos usar la interfaz proporcionada por POI para obtener el contenido del documento, analizar los datos en el documento usted mismo y obtener en qué párrafo se encuentra la imagen. Por supuesto, también puede saber qué elemento de ejecución se encuentra la imagen.
2. Realización
paquete com.szdfhx.reportstatistic.util; import com.microsoft.schemas.vml.ctshape; importar org.apache.poi.xwpf.usermodel.xwpfparagraph; import org.apache.poi.xxx.usermodel.xwpfpicturedata; import org.apache.poi.xwpf.usermodel.xwpfrun; import org.apache.xmlbeans.xmlcursor; import org.apache.xmlbeans.xmlObject; import org.openxmlformats.schemas.drawingml.x2006.main.ctgraphicalObs; import org. org.openxmlformats.schemas.wordprocessingml.x2006.main.ctr; import java.util.arrayList; import java.util.list; import java.util.list; import java.util.map; clase pública xwpfutils {// obtenga todos los índices de imagen en un cierto párrafo público; ReadImageInparagraph (xwpfpargraph párrafo) {// lista de índice de imágenes <string> imageBundLelist = new ArrayList <String> (); // Toda la lista XWPFRUN <XWPFRUN> en PARAGRAPH RunList = PARAGRAPH.GETRUNS (); for (xwpfrun run: runList) {// xwpfrun es su propio atributo generado por POI después de analizar el elemento XML. No se puede analizar a través de XML. Debe convertirse en CTR Ctr Ctr = run.getCtr (); // Transacción de elementos infantiles xmlcursor c = ctr.newcursor (); // Esto es para obtener todos los elementos infantiles: C.SelectPath ("./*"); while (c.tonextselection ()) {xmlObject o = c.getObject (); // Si el elemento infantil está en forma de <w: dibujo>, use ctdrawing para guardar la imagen si (o instancia de ctdrawing) {ctdrawing dibujo = (ctdrawing) o; Ctinline [] ctinlines = dibujo.getInlineArray (); para (ctinline ctinline: ctinlines) {ctgraphicalObject Graphic = ctinline.getGraphic (); // xmlcursor cursor = graphic.getgraphicData (). NewCursor (); cursor.selectpath ("./*"); while (cursor.tonextselection ()) {xmlObject xmlObject = cursor.getObject (); // Si el elemento infantil está en la forma <pic: pic> if (xmlObject instanceOf ctpicture) {org.openxmlformats.schemas.drawingml.x2006.picture.ctpicture = (org.openxmlformats.schemas.drawingml.x2006.picture.cture // Obtener el atributo del elemento ImageBundLelist.Add (image.getBlipFill (). GetBlip (). GetEmbed ()); }}}}} // use cTobject para guardar la imagen // <w: objeto> form if (o instanceof cTObject) {ctObject object = (cTObject) o; System.out.println (objeto); 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; }}En primer lugar, necesitamos proponer la encapsulación de elementos XML por XWPF:
<w: documento> correspondiente a la clase XWPFDocument
<w: ejecutar> correspondiente a la clase XWPFRUN
Básicamente, solo corresponde a la capa de ejecución. Debido a que hay muchos elementos infantiles de Run, ya no hay ninguna encapsulación y definición en el siguiente nivel.
Por lo tanto, solo podemos obtener todos los objetos XWPFrun convertidos en su definición XML: objetos CTR. Finalmente, use CTR para leer y analizar el contenido del elemento de ejecución y obtener el índice de la imagen.
La segunda cosa de la que hablar es la definición de todo el elemento XML:
Podemos ver que POI usa XML analizado por la tecnología XMLBeans bajo Apache. Si no discute las tecnologías relacionadas en profundidad, debe comprender dos puntos clave:
1: Todos los elementos en el documento XML están encapsulados por el XMLBean y heredar una interfaz XMLObject, por lo que esta clase puede usarse para recibir los elementos infantiles adquiridos;
2: El transversal de elementos se realiza a través de XMLCursor. La adquisición específica de elementos infantiles se controla en función del atributo SelectPath del objeto XMLCursor. Cuando el SelectPath es "./*", se define como atravesando elementos infantiles;
Por lo tanto, se escribe de la siguiente manera: puede atravesar los elementos infantiles del elemento actual y verificar el tipo de elemento infantil:
Ctr ctr = run.getctr (); // transule los elementos infantiles xmlcursor c = ctr.newcursor (); // Esto es para obtener todos los elementos infantiles: c.selectpath ("./*"); while (c.tonextselection ()) {xmlObject o = c.getObject (); // Si el elemento infantil está en la forma <w: dibujo>, use ctdrawing para guardar la imagen si (o instancia de ctdrawing) {ctdrawing dibujo = (ctdrawing) o;Finalmente, puede tener preguntas, ¿no este elemento <w: dibujar> define una imagen?
Entonces
if (o instancia de cTobject) {CTOBject Object = (CTObject) o; ...}¿Para qué se usa la segunda condición de juicio?
Deberías haberlo adivinado
¡Así es! Además de <W: Drawing>, el XML en el documento DOCX también se puede usar para definir la imagen.
¿Por qué solo hay estos dos?
Debido a que solo usé el primer método para analizar, descubrí que algunas imágenes se perdieron, así que encontré el segundo método ... ¿tal vez hay más de dos? No sé, de todos modos, no hay problema para mí en este momento.
¿Quizás usted, que son inteligentes, han encontrado más situaciones en la práctica?
Luego, utilizando el método de análisis XML mencionado anteriormente, creo que puede leerlo correctamente y obtener el valor de índice que desee.
Amplielo un poco. Si hay otras API que no son proporcionadas por POI, ¿podemos también implementarlas a través de la tecnología de análisis XML? Esto requiere que exploremos en la práctica. Creo que el tiempo nos dará la respuesta.
De acuerdo, ahora tenemos el valor del índice, entonces, ¿cómo obtenemos los recursos de imagen?
POI proporciona métodos preparados:
Hay GetPicturedAtabyID (imagen de cadena) en la clase XWPFDocument;
El método puede obtener el objeto XWPFPICTruyate, que es el recurso de imagen.
Para operaciones específicas, consulte las publicaciones y API de blog relevantes, que no se introducirán en detalle aquí.
3. Prueba:
Código para probar usando JUnit4:
paquete com.szdfhx.reportstatistic.util; importar org.apache.commons.collections.collectionutils; importar org.apache.commons.lang.stringutils; importar org.apache.poi.xwpf.usermodel.xwpfdocument; importar; importación; org.apache.poi.xwpf.usermodel.xwpfparagraph; import org.apache.poi.xwpf.usermodel.xwpfpicturedata; importar org.junit.test; import java.io.fileinputstream; import java.io.ioexception; import java.io.inputstream; importar; 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//My Blog//Java parsing word, get the image location in the documento // ejemplo.docx "); XWPFDocument XWPFDocument = new XWPFDocument (in); Lista <XWPFPARAPH> PARAGRAPHLIST = XWPFDocument.getParraphs (); System.out.println ("Índice de imagen/t | nombre de imagen/t | contenido de un párrafo de texto en la imagen/t"); System.out.pringln ("--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- if (CollectionUtIls.IsNotEmty (ImageBundLelist)) {for (String PictureId: ImageBundLelist) {XWPFPicturedata Picturedata = XWPFDocument.getPicturedAdAbyId (imageId); System.out.println (PictureID + "/t |" + ImageName + "/t |" + LastPraphtext);Mostrar resultados:
El uso de nombres de imágenes aquí significa que he obtenido los recursos correspondientes. De hecho, si está familiarizado con el contenido del artículo anterior, encontrará que el nombre de la imagen es en realidad el nombre completo de todas las imágenes en la carpeta Word/Media.
En el objeto XWPFPicturedata correspondiente, los datos binarios de la imagen se pueden obtener a través de la propiedad getData (), de modo que pueda guardarlos en la base de datos o en su carpeta local.
4. Otros:
Hablando de esto, el segundo problema mencionado al principio se ha resuelto aquí.
Entonces, ¿qué debo hacer con la primera pregunta?
Si su sistema no requiere alta velocidad, entonces mi consejo es convertir el documento DOC en documento DOCX para analizar: POI tiene una API madura que hacer
Si desea considerar el rendimiento, debe escribir dos conjuntos de métodos para analizar el documento.
Entonces ... ¿cómo obtener la posición relativa de la imagen en un documento de Word de tipo DOC?
No lo sé ... ¿o ven y dime?
En la palabra de análisis de Java anterior, el método para obtener la ubicación de la imagen en el documento es todo el contenido que comparto con usted. Espero que pueda darle una referencia y espero que pueda apoyar más a Wulin.com.