مقدمة (مقدمة خلفية):
Apache POI هو المشروع المفتوح المصدر التالي لمؤسسة Apache ، ويستخدم لمعالجة المستندات في سلسلة Office ويمكنه إنشاء مستندات وتواجها بتنسيقات Word و Excel و PPT.
هناك نوعان من التقنيات لمعالجة مستندات الكلمات ، وهما HWPF (.DOC) و XWPF (.DOCX). إذا كنت على دراية بهاتين التقنيتين ، فيجب أن تكون قادرًا على فهم ألم استخدام Java لتحليل مستندات Word.
اثنان من أكبر المشاكل هي:
الأول هو أن هاتين الفئتين ليس لهما فئة أولية موحدة (XSSF و HSSF المجاور يلقي عيونهما المزدحمة) ، لذلك لا يمكنهما إجراء برمجة الواجهة بنفس التنسيق ؛
والثاني هو أنه لا توجد واجهة للموضع النسبي للصور في المستند في واجهة برمجة التطبيقات الرسمية ، مما يؤدي إلى حقيقة أنه على الرغم من أنه يمكنك الحصول على جميع الصور في المستند ، لا يمكنك معرفة مكان هذه الصور. في المستقبل ، لن تتمكن من إدراج الصور في الموضع الصحيح.
بالنسبة للنقطة الأولى ، ليس لدي خيار سوى دراسة التقنيات الأخرى ذات الصلة ، مثل Jacob ، Doc4J ، وما إلى ذلك ، لمعرفة ما إذا كانت هناك أي حلول أخرى ، ولكن يبدو أن DOC4J قادر على معالجة وثائق 2007 (.DOCX).
بالنسبة للنقطة الثانية ، فإن هذا المقال سوف يعطيني حل المؤلف. في الواقع ، هذا هو الغرض من كتابتي هذه المقالة.
ملاحظة: انظر فقط إلى الفصل 2 والفصل 3 إذا كنت تطلب ببساطة السرعة ؛
1. المعرفة التحضير
1. التنسيقان لمستندات الكلمة يتوافق مع طريقتين تخزين مختلفان
كما نعلم جميعًا ، تحتوي مستندات Word على تنسيقان للتخزين: DOC و DOCX
DOC: يسمى عادة Word2003 ، والذي يستخدم بيانات التخزين الثنائية ؛ هذا ليس محور مناقشتنا اليوم.
DOCX: Word2007 ، يستخدم XML لتخزين البيانات والتنسيق.
ربما ستسأل ، لماذا هو تنسيق XML الذي من الواضح أنه وثيقة تنتهي في DOCX؟
الأمر بسيط للغاية: يمكنك فقط تحديد ملف docx ، انقر بزر الماوس الأيمن لفتحه باستخدام أداة الضغط ، ويمكنك الحصول على بنية دليل مثل هذا:
لذلك تعتقد أن DOCX مستند كامل ، ولكن في الواقع هو مجرد ملف مضغوط. (docx:؟ _؟)
2. تنسيق تعريف XML في مستندات الكلمات:
من المثال السابق ، تعلمنا أن مستندات DOCX تستخدم ملفات مضغوطة ، أي XML لوصف البيانات. فكيف يتم تعريف البيانات في مستندات Word على وجه التحديد؟
بسبب المساحة ، لن يتم وصف المستند المضغوط بأكمله بالتفصيل هنا. سأقدم فقط بإيجاز ملف/مجلدات:
أولاً ، ملف document.xml في دليل Word ، وهو تعريف محتوى المستند بأكمله ؛
والثاني هو مجلد الوسائط في دليل الكلمة. يمكنك تخمين محتوى الوسائط المتعددة في المستند من خلال النظر في الاسم:
الشكل 3: Word/Document.xml (تحديد محتوى المستند)
الشكل 4: المحتويات تحت مجلد الكلمة/الوسائط
فيما يلي بعض المحتويات الرئيسية لمستند المستند. xml:
ج: توثيق الهيكل العام تعريف:
<W: Document MC: ignentate = "W14 W15 WP14" Xmlns: M = "http://schemas.openxmlformats.org/offperycument/2006/math Xmlns: o = "urn: schemas-microsoft-com: Office: Office" xmlns: w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" Xmlns: W15 = "http://schemas.microsoft.com/office/word/2012/wordml" xmlns: wp = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingdrawing" xmlns: wp14 = "http://schemas.microsoft.com/office/word/2010/wordprocessing" xmlns: wpg = "http://schemas.microsoft.com/office/word/2010/wordprocessingcanvas" xmlns: wpi = "http://schemas.microsoft.com/office/word/2010/wordprocessingink" xmlns: wpscustomData = "http://www.wps.cn/officedocument/2013/wpscustomdata"> <w: body> <w: p> <w: ppr> <w: pstyle w: val = "2" </w: pstyle> <w: keeplines w: val = "0"> </w: keeplines> <w: WidowControl> </w: WidowControl> <w: cumpresslinenumbers w: val = "0"> </w <W: Left W: color = "Auto" W: Space = "0" W: val = "none"> </w: bottom> <w: right w: color = "auto" w: "0" w: sz = "0" w: val =
ب: محتوى فقرة المستند:
<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: cropresslinenumbers> <w: pbdr> <w: top w: color = "auto" w: space = "0" w: sz = "0"> </w: top> <w: left w: color = "auto" w: "0" w: sz = "0" w: val = "none"> </w: W: sz = "0" w: val = "none"> </w: أسفل> <w: right w: color = "auto" w: space = "0" w: sz = "0" w: val = "none"> </w: rewe> </w: pbdr> <w: shd w: flug = "fafafa" w: val = "clear> W: QuortaUtospacing = "0" W: قبل = "150" W: beforeaUtospacing = "0" w: line = "378" w: linerule = "atleast"> </w: التباعد> <w: W: cs = "verdana" w: hansi = "verdana" w: hint = "default"> </w: rfonts> <w: iw: val = "0"> </w: </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: " 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: val = "21"> </w: sz> <w: szcs w: val = "21"> </w: szcs> <w: bdr w: color = "auto" w: space = "0" w: sz = "0 </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: caps w: W: val = "404040"> </w: color> <w: التباعد w: val = "0"> </w: التباعد> <w: sz w: val = "21"> </w: sz> <w: szcs w: val = "21" </w: szcs> <w: bdr w: color = " 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" dist = "0" cy = "5543550"> </wp: extent> <wp: effectextent b = "0" l = "0" r = "0" t = "0" nochangeaspect = "1" xmlns: a = "http://schemas.openxmlformats.org/drawingml/2006/main"> </a: graphicframelock> </wp: cnvgraphicframepr> <a: graphic xmlns: a = "http://schemas.openxmlformats.org/drawingml/2006/main xmlns: pic = "http://schemas.openxmlformats.org/drawingml/2006/picture"> <pic: nvpicpr> <pic: cnvpr descr = "img_256" id = "1" name = "picture 1" nochangeaspect = "1"> </a: piclocks> </pic: cnvpicpr> </pic: nvpicpr> <pic: blipfill> <a: blip r: embed = "rid4"> </a: blipfill> <a: struct> <a: flowRect> </a: <a: Off x = "0" y = "0"> </a: Off> <a: ext cx = "5543550" cy = "5543550"> </a: ext> </a: xfrm> <a: prstgeom prst = "rect"> <a: ln w = "9525"> <a: nofill> </a: nofill> </ a: ln> </pic: sppr> </
إذا كنت مهتمًا ، فيمكنك إلقاء نظرة على رموز XML الثلاثة أعلاه. سأعطي الاستنتاج مباشرة هنا:
Word document shema file: xmlns: w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
عقدة جذر المستند: <w: document> تحدد بداية المستند بأكمله
<w: body> هي عقدة الطفل للوثيقة والمحتوى الرئيسي للوثيقة
<W: P> Body Child Node ، فقرة ، هي الفقرة في وثيقة Word
<W: R> Child Node of P element ، يحدد تشغيل فقرة بنفس التنسيق في الفقرة
<w: t> العقدة الفرعية لعقدة عنصر التشغيل هي محتوى المستند.
<W: Drawing> Child Node of the Run ، تحدد الصورة:
<W: INLINE> رسم العقد الفرعية ، لم يتم إجراء بحث متعمق على التطبيق المحدد.
<a: graphic> تحديد محتوى الصورة
<pic: blipfill> هذه عقدة طفل لمستند الرسوم ، والتي تحدد فهرس محتوى الصورة. على وجه التحديد ، يمكن لـ POI الحصول على الموارد المقابلة للصورة بناءً على هذا الاسم ، ومفتاح الحصول على موقع صورة المستند هنا.
بشكل عام ، تتمثل مستندات DOCX في تحليل XWPF في تحليل مستند XML ، وحفظ جميع العقد ، ثم تحويلها إلى خصائص أكثر فائدة ، مما يوفر لاستخدام API للمستخدمين.
حتى نتمكن من استخدام الواجهة التي توفرها لنا من قبل POI للحصول على محتوى المستند ، وتحليل البيانات الواردة في المستند بنفسك ، والحصول على الفقرة الموجودة في الصورة. بالطبع ، يمكنك أيضًا معرفة العنصر الذي تقع فيه الصورة وراءها.
2. الإدراك
package com.szdfhx.reportstatistic.util ؛ استيراد com.microsoft.schemas.vml.ctshape ؛ استيراد org.apache.poi.xwpf.usermodel.xwpfparagraph ؛ import org.apache.poi.xwpf.usermodel.xwpfpuctureata org.apache.poi.xwpf.usermodel.xwpfrun ؛ استيراد org.apache.xmlbeans.xmlcursor ؛ استيراد org.apache.xmlbeans.xmlobject ؛ استيراد org.openxmlformats.schemas.drawingml.x2006.main.ctgraphic. org.openxmlformats.schemas.drawingml.x2006.picture.ctpicture ؛ استيراد org.openxmlformats.schemas.drawingml.x2006.main.ctdrawing ؛ import org.openxmlformats.schemas.wordprocessingml.x2006.main.main org.openxmlformats.schemas.wordprocessingml.x2006.main.ctr ؛ استيراد java.util.arraylist ؛ استيراد java.util.list ؛ استيراد java.util.list readImageInParagraph (فقرة xwpfparagraph) {// قائمة فهرس الصورة <string> imageBundLelist = new ArrayList <string> () ؛ . لـ (XWPFRUN RUN: Runlist) {// XWPFRUN هي سمة خاصة بها تم إنشاؤها بواسطة POI بعد تحليل عنصر XML. لا يمكن تحليلها من خلال XML. يجب تحويله إلى ctr ctr ctr = run.getCtr () ؛ // معاملة عناصر الطفل xmlcursor c = ctr.newcursor () ؛ // هذا هو الحصول على جميع عناصر الطفل: c.selectpath ("./*") ؛ بينما (c.tonextselection ()) {xmlobject o = c.getObject () ؛ // إذا كان العنصر الفردي في شكل <w: drawing> ، استخدم ctdrawing لحفظ الصورة إذا (o extutionof ctdrawing) {ctdrawing drawing = (ctdrawing) o ؛ ctinline [] ctinlines = drawing.getInlineArray () ؛ لـ (ctinline ctinline: ctinlines) {ctGraphicalObject graphic = ctinline.getGraphic () ؛ // xmlcursor cursor = graphic.getGraphicData (). newCursor () ؛ Cursor.SelectPath ("./*") ؛ بينما (cursor.tonextselection ()) {xmlobject xmlobject = cursor.getObject () ؛ // إذا كان العنصر الطفل في النموذج <pic: pic> إذا (xmlobject extryof ctpicture) {org.openxmlformats.schemas.drawingml.x2006.picture.ctpicture picture = (org.openxmlformats.schemas.drawingml.x2006.picture. // احصل على سمة العنصر ImageBundLelist.add (picture.getBlipFill (). getBlip (). getembed ()) ؛ }}}}} // استخدم ctobject لحفظ الصورة // <w: object> if (o eastyof ctobject) {ctobject object = (ctobject) o ؛ system.out.println (كائن) ؛ xmlcursor w = object.newcursor () ؛ W.SelectPath ("./*") ؛ بينما (w.tonextselection ()) {xmlobject xmlobject = w.getObject () ؛ if (xmlobject extryof ctshape) {ctshape mape = (ctshape) xmlobject ؛ ImageBundLelist.Add (lape.getimagedataarray () [0] .getID2 ()) ؛ }}}}} إرجاع ImageBundLelist ؛ }}بادئ ذي بدء ، نحتاج إلى اقتراح تغليف عناصر XML بواسطة XWPF:
<W: Document> المقابلة لفئة XWPFDOCINGUME
<W: Run> المقابلة لفئة XWPFRUN
في الأساس ، فإنه يتوافق فقط مع طبقة التشغيل. نظرًا لوجود العديد من عناصر التشغيل للأطفال ، لم يعد هناك أي تغليف وتعريف على المستوى التالي.
لذلك يمكننا فقط الحصول على جميع كائنات XWPFRUN التي تم تحويلها إلى تعريف XML الخاص بها: كائنات CTR. أخيرًا ، استخدم CTR لقراءة وتحليل محتويات عنصر التشغيل والحصول على فهرس الصورة.
الشيء الثاني الذي يجب الحديث عنه هو تعريف عنصر XML بأكمله:
يمكننا أن نرى أن POI يستخدم XML محجوفًا بواسطة تقنية XMLBeans تحت Apache. إذا لم تناقش التقنيات ذات الصلة بعمق ، فيجب أن تفهم نقطتين رئيسيتين:
1: يتم تغليف جميع العناصر في مستند XML بواسطة Xmlbean ويرث واجهة Xmlobject ، بحيث يمكن استخدام هذه الفئة لتلقي العناصر الفرعية المكتسبة ؛
2: يتم اجتياز العنصر من خلال XMLCursor. يتم التحكم في عملية الاستحواذ المحددة للعناصر الفرعية بناءً على سمة SelectPath لكائن XMLCursor. عندما يكون SelectPath "./*" ، يتم تعريفه على أنه عبور عناصر الأطفال ؛
لذلك تتم كتابته على النحو التالي: يمكن أن يعبر عناصر الطفل للعنصر الحالي والتحقق من نوع العنصر الطفل:
ctr ctr = run.getctr () ؛ // نقل عناصر الطفل xmlcursor c = ctr.newcursor () ؛ // هذا هو الحصول على جميع عناصر الطفل: c.selectpath ("./*") ؛ بينما (c.tonextselection ()) {xmlobject o = c.getObject () ؛ // إذا كان العنصر الفرعي في النموذج <w: drawing> ، استخدم ctdrawing لحفظ الصورة إذا (o exitalof ctdrawing) {ctdrawing drawing = (ctdrawing) o ؛أخيرًا ، قد يكون لديك أسئلة ، ألم يحدد هذا العنصر <W: Drawing> صورة؟
لذا
if (o مثيل ctobject) {ctobject object = (ctobject) o ؛ ...}ما هو شرط الحكم الثاني المستخدمة؟
يجب أن تفكر في ذلك
هذا صحيح! بالإضافة إلى <w: الرسم> ، يمكن أيضًا استخدام XML في مستند DOCX لتحديد الصورة.
لماذا يوجد فقط هذين؟
لأنني استخدمت الطريقة الأولى فقط لتحليلها ، وجدت أن بعض الصور قد فقدت ، لذلك وجدت الطريقة الثانية ... ربما هناك أكثر من اثنين؟ لا أعرف ، على أي حال ، لا توجد مشكلة بالنسبة لي في الوقت الحالي.
ربما واجهت أنت ذكي ، المزيد من المواقف في الممارسة؟
بعد ذلك ، باستخدام طريقة تحليل XML المذكورة أعلاه ، أعتقد أنه يمكنك قراءتها بشكل صحيح والحصول على قيمة الفهرس التي تريدها.
توسيعها قليلا. إذا كان هناك واجهات برمجة التطبيقات الأخرى التي لا توفرها POI ، فهل يمكننا أيضًا تنفيذها من خلال تقنية تحليل XML؟ هذا يتطلب منا استكشاف في الممارسة العملية. أعتقد أن الوقت سيعطينا الجواب.
حسنًا ، لدينا الآن قيمة الفهرس ، فكيف نحصل على موارد الصورة؟
يوفر POI طرقًا جاهزة:
هناك getPicturedataByid (صورة سلسلة) في فئة XWPFDOCUMITY ؛
يمكن أن تحصل الطريقة على كائن XWPFPICTRUEDATE ، وهو مورد الصورة.
بالنسبة لعمليات محددة ، يرجى الرجوع إلى منشورات المدونة وواجهة برمجة التطبيقات ذات الصلة ، والتي لن يتم تقديمها بالتفصيل هنا.
3. الاختبار:
رمز للاختبار باستخدام JUNIT4:
package com.szdfhx.reportstatistic.util ؛ import org.apache.commons.collections.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 ؛ java.util.collections ؛ استيراد java.util.list ؛ استيراد org.junit.assert static وثيقة // example.docx ") ؛ xwpfdocument xwpfdocument = new xwpfdocument (in) ؛ قائمة <xwpfparagraph> paragraphlist = xwpfdocument.getParaphs () ؛ System.out.println ("Image INDEX/T | Image Name/T | محتوى فقرة النص على الصورة/t") ؛ System.out.pringln("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ if (collectionUtils.isnotempty (ImageBundLelist) {for (pictureid: imageBundLelist) {xwpfpicturedata picturedata = xwpfdocument.getpictaByid (pictionId) ؛ System.out.println (Pictureid + "/T |" + ImageName + "/T |" + LastParagraphtext) ؛نتائج إظهار:
استخدام أسماء الصور هنا يعني أنني حصلت على الموارد المقابلة. في الواقع ، إذا كنت على دراية بمحتوى المقالة السابقة ، فستجد أن اسم الصورة هو في الواقع الاسم الكامل لجميع الصور في مجلد Word/Media.
في كائن XWPFPICTUREATATA المقابل ، يمكن الحصول على البيانات الثنائية للصورة من خلال خاصية getData () ، بحيث يمكنك حفظها في قاعدة البيانات أو المجلد المحلي الخاص بك!
4. آخرون:
الحديث عن هذا ، تم حل المشكلة الثانية المذكورة في البداية هنا.
لذا ، ماذا علي أن أفعل مع السؤال الأول؟
إذا كان نظامك لا يتطلب سرعة عالية ، فإن نصيحتي هي تحويل مستند DOC إلى مستند DOCX إلى PARSE - POI لديه واجهة برمجة تطبيقات ناضجة للقيام بها
إذا كنت ترغب في التفكير في الأداء ، فيجب عليك كتابة مجموعتين من الأساليب لتحليل المستند.
لذا ... كيف تحصل على الموضع النسبي للصورة في مستند Word Word Doc؟
لا أعرف ... أو تعال وأخبرني؟
في كلمة تحليل Java أعلاه ، فإن طريقة الحصول على موقع الصورة في المستند هي كل المحتوى الذي أشاركه معك. آمل أن تتمكن من إعطائك مرجعًا وآمل أن تتمكن من دعم wulin.com أكثر.