ПРЕДИСЛОВИЕ (Фоновое введение):
Apache Poi является следующим проектом с открытым исходным кодом Фонда Apache, используемым для обработки документов в офисной серии и может создавать и анализировать документы в форматах Word, Excel и PPT.
Есть две технологии для обработки документов Word, а именно HWPF (.doc) и xwpf (.docx). Если вы знакомы с этими двумя технологиями, вы сможете понять боль от использования Java для разбора документов Word.
Две из самых больших проблем:
Во -первых, эти два класса не имеют унифицированного родительского класса и интерфейса (XSSF и HSSF по соседству бросают свои презрительные глаза), поэтому они не могут выполнять интерфейсное программирование в том же формате;
Во -вторых, нет интерфейса для относительной позиции изображений в документе в официальном API, что приводит к тому, что, хотя вы можете получить все изображения в документе, вы не можете знать, где эти картинки. В будущем вы не сможете вставить изображения в правильную позицию.
Что касается первого пункта, у меня нет выбора, кроме как изучать другие связанные технологии, такие как Джейкоб, DOC4J и т. Д., Чтобы увидеть, есть ли другие решения, но DOC4J, похоже, способен обрабатывать документы 2007 года (.docx).
Для второго пункта эта статья даст мне решение автора. На самом деле, это также цель моего написания этой статьи.
Примечание: просто посмотрите на главу 2 и главу 3, если вы просто просите скорости;
1. Подготовка знаний
1. Два формата документов Word соответствуют двум различным методам хранения
Как мы все знаем, документы Word имеют два формата хранения: DOC и DOCX
DOC: Это обычно называют Word2003, который использует бинарные данные хранения ; Это не в центре нашего обсуждения сегодня.
DOCX: Word2007, использует XML для хранения данных и формата.
Может быть, вы спросите, почему это формат XML, который, очевидно, является документом, заканчивающимся в DOCX?
Это очень просто: вы можете просто выбрать файл DOCX, щелкните правой кнопкой мыши, чтобы открыть его с помощью инструмента сжатия, и вы можете получить структуру каталогов, как это:
Таким образом, вы думаете, что Docx является полным документом, но на самом деле это просто сжатый файл. (DOCX:? _?)
2. Формат определения XML в документах Word:
Из предыдущего примера мы узнали, что документы DOCX используют сжатые файлы, то есть XML для описания данных. Итак, как конкретно определяются данные в документах Word?
Из -за пространства весь сжатый документ не будет подробно описан здесь. Я лишь кратко представлю два файла/папки:
Во -первых, файл document.xml в каталоге Word, который является определением всего содержимого документа;
Второе - это папка мультимедиа в справочнике. Вы можете догадаться о мультимедийном контенте в документе, посмотрев на имя:
Рисунок 3: word/document.xml (определить содержимое документа)
Рисунок 4: Содержание под папкой Word/Media
Ниже приведены некоторые ключевые содержания документа Document.xml:
A: документ общий определение структуры:
<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/offeencement/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: vord" xmlns: w14 = "http://schemas.microsoft.comsml.combice/fors.20ls. 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/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/2010/wordprocessingshape" xmlns: wpscustomdata = "http://www.wps.cn/officeedocument/2013/wpscustomdata"> <w: Body> <w: P> <w: ppr> <w: pstyle w: val = "2"> </w: pStyle> <W: geatenx <w:keeplines w:val="0"> </w:keeplines> <w:widowcontrol> </w:widowcontrol> <w:suppresslinenumbers w:val="0"> </w:suppresslinenumbers> <w:pbdr> <w:top w:color="auto" w:space="0" w:sz="0" w:val="none"> </w:top> <W: слева w: color = "auto" w: space = "0" w: val = "non"> </w: внизу> <w: справа w: color = "auto" w: space = "0" w: sz = "0" w: val = "none"> </w: справа> </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: Spearlines> <w: widowcontrol> </w: widowcontrolol> <w: Sppressline = wydowcontrol> </w: widowcontrolol> </w: spistresslineNumbers> <w: Pbdr> <W: top W: color = "auto" w: space = "0" w: sz = "0"> </w: top> <w: левый w: color = "auto" w: space = "0" w: sz = "0"> w: val = "none"> </w: w: внизу w: aut = "aut =" w: "w:" w: "w:" w: "w:" w: "w:" w: a aut ". w: sz = "0" w: val = "none"> </w: внизу> <w: справа w: color = "auto" w: space = "0" w: sz = "0" w: val = "none"> </w: справа> </w: pbdr> <w: shd w: fill = "fafafa" w: val = "> </w: shd> <w: wpocte = w: w: w: w: w: w: w:" w: w: "w: w:" w: w: "w: w:" w: w: "w: w: w: w: w: w:" W: Afterautospacing = "0" w: до = "150" w: beforeautospaging = "0" w: line = "378" w: linerule = "Ateleast"> </w: расстояние> <w: ind w: firstline = "0" w: left = "0" w: right = "0"> </w: ind> <w: rpr> <w: rfonts w: rfints " 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: al: val = "404040"> </w: w: w: w: w: w: w: w: w: spocks> </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: asci = "verdana" w: cs "vpr> <w: rfonts w: asci =" w: cs "vp:" 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: spode w: val al al ". 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:fill="FAFAFA" w:val="clear"> </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: caps w: val = "0" 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:color="auto" w:space="0" w:sz="0"" w: val = "none"> </w: bdr> <w: shd w: fill = "fafafa" w: val = "clear"> </w: shd> </w: rpr> <w: рисунок> <wp: inline distb = "0" distl = "114300" dist = "114300" dist = "0"> <wp: extent cx = "55555550" 114300 ". 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: cnvgrapr name = "> </wp: docpr> <wp: cnvgrap1> </wp: docpr> <wp: cnvgrap1> </wp: docpr> <wp: cnvgrapr. <A: GraphicFramelocks nochangeaSpect = "1" xmlns: a = "http://schemas.openxmlformats.org/drawingml/2006/main"> </a: graphicframelocks> </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"> <ic: nvpicpr> <pic: cnvpr descr = "img_256" id = "1" name = "picture 1" nochangeaspepe = "1"> </a: piclocks> </pic: cnvpicpr> </pic: nvpicpr> <ic: blipfill> <a: blip r: embed = "rid4"> </a: blip> <a: retepip> <a: filprect> </a: filpRect> </a: streath> </pic: blipfil <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: prstgem> <A: ln w = "9525"> <a: nofill> </a: nofill> </a: ln> </pic: sppr> </pic: pic> </a: graphicdata> </a: график> </wp: inline> </w: рисунок> </w: r>
Если вы заинтересованы, вы можете посмотреть на три вышеуказанные коды XML. Я сделаю вывод прямо здесь:
Файл документа Word SHEM: xmlns: w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
Корневой узел документа: <W: документ> Определяет начало всего документа
<w: Body> - это дочерний узел документа и основное содержание документа
<W: P> Body Child Node, абзац, это абзац в документе Word
<w: r> r> node of p ement, run определяет абзац с тем же форматом в абзаце
<W: T> Узел дочернего узла элемента прогона - это содержимое документа.
<w: рисунок> Детский узел элемента прогона, определяет изображение:
<W: Inline> Результат дочерних узлов, в конкретном приложении не было проведено подробные исследования.
<A: Graphic> Определить содержание изображения
<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.xwppparagraph; import.apache.poi.xwpf.usermodel.xwpppicturedata; org.apache.poi.xwpf.usermodel.xwpfrun; импорт org.apache.xmlbeans.xmlcursor; import org.apache.xmlbeans.xmlobject; import org.openxmlformats.schemas.drawingml.x2006.main.ctgraphicalobject; org.openxmlformats.schemas.drawingml.x2006.picture.ctpicture; импорт org.openxmlformats.schemas.drawingml.x2006.main.ctdrawing; import.openxmlformats.schemas.wordprocessml.x2006.comain org.openxmlformats.schemas.wordprocessingml.x2006.main.ctr; import java.util.arraylist; import java.util.list; import java.util.list; импорт java.util.map; public xwpfutils {// Получите все Imade Indexes в определенных параграфах. readimageinparagraph (xwpfparagraph paragraph) {// Список индекса изображений <string> imagebundlelist = new ArrayList <string> (); // все xwpfrun list <swpfrun> в пункте runlist = paragraph.getruns (); Для (xwpfrun run: runlist) {// xwpfrun - это его собственный атрибут, сгенерированный POI после анализа элемента XML. Это не может быть проанализировано через XML. Его необходимо преобразовать в CTR CTR CTR = Run.getCtr (); // транзакция детских элементов xmlcursor c = ctr.newcursor (); // это чтобы получить все детские элементы: c.selectpath ("./*"); while (c.tonextselection ()) {xmlobject o = c.getObject (); // Если дочерний элемент находится в форме <W: чертеж>, используйте CTDRAWING, чтобы сохранить изображение, если (o InstactOf ctDrawing) {ctdrawing trawn = (ctdrawing) o; Ctinline [] ctinlines = trawn.getInlinearray (); для (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 ancessionof ctpicture) {org.openxmlformats.schemas.drawingml.x2006.picture.ctpicture picture // Получить атрибут элемента imagebundlelist.add (picture.getblipfill (). Getblip (). Getembed ()); }}}}} // Использование ctobject для сохранения изображения // <w: объект> форма if (o ancessionof ctobject) {ctobject object = (ctobject) o; System.out.println (Object); Xmlcursor w = object.newcursor (); w.selectpath ("./*"); while (w.tonextselection ()) {xmlobject xmlobject = w.getObject (); if (xmlobject ancessionof ctshape) {ctshape shape = (ctshape) xmlobject; imagebundlelist.add (shape.getimagedataarray () [0] .getid2 ()); }}}}} return imagebundlelist; }}Прежде всего, нам нужно предложить инкапсуляцию элементов XML с помощью XWPF:
<W: Документ> Соответствует классу XWPFDOCUMENT
<W: Запуск> Соответствует классу XWPFRUN
По сути, это только соответствует слою пробега. Поскольку существует много дочерних элементов пробега, на следующем уровне больше нет никакой инкапсуляции и определения.
Таким образом, мы можем только преобразовать все объекты XWPFRUN в его определение XML: CTR -объекты. Наконец, используйте CTR для чтения и проанализирования содержимого элемента Run и получить индекс изображения.
Вторая вещь, о которой можно поговорить, это определение всего элемента XML:
Мы видим, что POI использует XML, проанализированную технологией XMLBeans под Apache. Если вы не обсуждаете связанные с ними технологии, вы должны понимать два ключевых момента:
1: Все элементы в документе XML инкапсулируются XMLBEAN и наследуют интерфейс XMLOBJECT, поэтому этот класс может использоваться для получения приобретенных дочерних элементов;
2: Триверсл элемента выполняется через XMLCursor. Конкретное получение детских элементов контролируется на основе атрибута SelectPath объекта Xmlcursor. Когда SelectPath будет "./*", он определяется как пересекающие детские элементы;
Таким образом, это написано следующим образом: он может пересечь детский элементы текущего элемента и проверить тип дочернего элемента:
Ctr ctr = run.getctr (); // транслируют дочерние элементы xmlcursor c = ctr.newcursor (); // Это для получения всех дочерних элементов: c.selectpath ("./*"); while (c.tonextselection ()) {xmlobject o = c.getObject (); // Если дочерний элемент находится в форме <w: чертеж>, используйте ctdrawing, чтобы сохранить изображение, если (o экземпляр ctdrawing) {ctdrawing trailm = (ctdrawing) o;Наконец, у вас могут быть вопросы, разве этот элемент <W: рисунок> не определяет изображение?
Так
if (o encessof ctobject) {ctobject object = (ctobject) o; ...}Для чего используется условие второго суждения?
Вы должны были догадаться
Это верно! В дополнение к <W: чертеж>, XML в документе DOCX также может использоваться для определения изображения.
Почему есть только эти два?
Поскольку я использовал только первый метод для анализа, я обнаружил, что некоторые картинки были потеряны, поэтому я нашел второй метод ... может быть, их более двух? Я не знаю, в любом случае, в данный момент у меня нет проблем.
Возможно, вы, кто умный, столкнулся с большим количеством ситуаций на практике?
Затем, используя метод анализа XML, упомянутый выше, я считаю, что вы можете правильно его прочитать и получить желаемое значение индекса.
Немного расширить это. Если есть другие API, которые не предоставляются POI, можем ли мы также реализовать их с помощью технологии анализа XML? Это требует от нас исследовать на практике. Я считаю, что время даст нам ответ.
Хорошо, теперь у нас есть значение индекса, так как же мы получаем ресурсы изображения?
POI предоставляет готовые методы:
В классе xwpfdocument есть getpicturedatabyid (String Picture);
Метод может получить объект xwpfpictruendate, который является ресурсом изображения.
Для конкретных операций, пожалуйста, обратитесь к соответствующим сообщениям в блоге и API, которые здесь не будут введены подробно.
3. Тест:
Код для тестирования с использованием junit4:
пакет com.szdfhx.reportstatistic.util; import org.apache.commons.collections.collectionutils; import org.apache.commons.lang.stringutils; import org.apache.poi.xwpf.usermodel.xwppffffement; import.apache.poi.xwpppplary.usmodel.xwppffffement; import.apache. org.apache.poi.xwpf.usermodel.xwpppicturedata; import org.junit.test; import java.io.fileinputstream; импорт java.io.ioexception; импорт java.io.InputStream; импорт java.Util.collections; импорт java.ut.list. XwpfutilStest {@Test public void readimageInparagraph () throws ioException {inputStream in = new FileInputStream ("d: // Document // My Blog // java parsing word, получите местоположение изображения в документе // avent.docx"); Xwpfdocument xwpfdocument = new xwpfdocument (in); Список <xwpfparagraph> paragraphlist = xwpfdocument.getParagraphs (); System.out.println ("Image Index/T | ИЗОБРАЖЕНИЕ Имя/T | Содержание параграфа текста на изображении/T"); System.out.pringln("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ if (collectiontils.isnotempty (imagebundlelist)) {for (String picture: imagebundlelist) {xwpfpicturedata pictureata = xwpfdocument.getpicturedatabyid (pictureid); System.out.println (picture + "/t |" + ImageName + "/t |" + LastParagraphtext);Покажите результаты:
Использование имен изображений здесь означает, что я получил соответствующие ресурсы. На самом деле, если вы знакомы с содержанием предыдущей статьи, вы обнаружите, что имя изображения на самом деле является полным именем всех изображений в папке Word/Media.
В соответствующем объекте xwpfpicturedata двоичные данные изображения могут быть получены через свойство getData (), чтобы вы могли сохранить его в базе данных или локальной папке!
4. Другие:
Говоря об этом, вторая проблема, упомянутая в начале, была решена здесь.
Итак, что мне делать с первым вопросом?
Если ваша система не требует высокой скорости, то я советую преобразовать документ DOC в документ DOCX для анализа - у POI есть зрелый API, чтобы сделать
Если вы хотите рассмотреть производительность, вам нужно написать два набора методов для анализа документа.
Итак ... как получить относительную позицию изображения в документе Word-Type Doc?
Я не знаю ... или, приходи и скажи мне?
В приведенном приведенном словом разбора Java метод получения местоположения изображения в документе - это все контент, которым я делюсь с вами. Я надеюсь, что вы можете дать вам ссылку, и я надеюсь, что вы сможете поддержать Wulin.com больше.