--- src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java (revision 793891) +++ src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java (working copy) @@ -21,26 +21,7 @@ import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlObject; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTInd; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTJc; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPBdr; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPTab; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPicture; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSdtContentRun; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSdtRun; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSpacing; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTextAlignment; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.STLineSpacingRule; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTextAlignment; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; import org.w3c.dom.NodeList; import org.w3c.dom.Text; @@ -107,6 +88,24 @@ if (o instanceof CTPTab) { text.append("\t"); } + if (o instanceof CTFtnEdnRef) { + CTFtnEdnRef ftn = (CTFtnEdnRef) o; + text.append("[").append(ftn.getId()).append(": "); + XWPFFootnote footnote = document.getFootnoteByID(ftn.getId()); + + boolean first = true; + + for (XWPFParagraph p : footnote.getParagraphs()) { + if (!first) { + text.append("\n"); + first = false; + } + + text.append(p.getText()); + } + + text.append("]"); + } } // Loop over pictures inside our --- src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRelation.java (revision 793891) +++ src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRelation.java (working copy) @@ -88,6 +88,12 @@ null, null ); + public static final XWPFRelation FOOTNOTE = new XWPFRelation( + null, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes", + null, + null + ); private XWPFRelation(String type, String rel, String defaultName, Class cls) { --- src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java (revision 793891) +++ src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java (working copy) @@ -19,6 +19,7 @@ import java.io.IOException; import java.io.OutputStream; import java.util.*; +import java.math.BigInteger; import org.apache.poi.POIXMLDocument; import org.apache.poi.POIXMLException; @@ -30,15 +31,7 @@ import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.OpenXML4JException; import org.apache.poi.openxml4j.opc.*; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTComment; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyles; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CommentsDocument; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.DocumentDocument; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.StylesDocument; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; import javax.xml.namespace.QName; @@ -60,6 +53,7 @@ protected List hyperlinks; protected List paragraphs; protected List tables; + protected Map footnotes; /** Handles the joy of different headers/footers for different pages */ private XWPFHeaderFooterPolicy headerFooterPolicy; @@ -87,6 +81,7 @@ comments = new ArrayList(); paragraphs = new ArrayList(); tables= new ArrayList(); + footnotes = new HashMap(); try { DocumentDocument doc = DocumentDocument.Factory.parse(getPackagePart().getInputStream()); @@ -94,6 +89,8 @@ CTBody body = ctDocument.getBody(); + initFootnotes(); + // filling paragraph list for (CTP p : body.getPArray()) { paragraphs.add(new XWPFParagraph(p, this)); @@ -118,7 +115,6 @@ } initHyperlinks(); - } catch (XmlException e) { throw new POIXMLException(e); } @@ -139,6 +135,19 @@ } } + private void initFootnotes() throws XmlException, IOException { + for(POIXMLDocumentPart p : getRelations()){ + String relation = p.getPackageRelationship().getRelationshipType(); + if(relation.equals(XWPFRelation.FOOTNOTE.getRelation())){ + FootnotesDocument footnotesDocument = FootnotesDocument.Factory.parse(p.getPackagePart().getInputStream()); + + for(CTFtnEdn ctFtnEdn : footnotesDocument.getFootnotes().getFootnoteArray()) { + footnotes.put(ctFtnEdn.getId(), new XWPFFootnote(this, ctFtnEdn)); + } + } + } + } + /** * Create a new SpreadsheetML package and setup the default minimal content */ @@ -205,6 +214,11 @@ return null; } + + public XWPFFootnote getFootnoteByID(BigInteger id) { + return footnotes.get(id); + } + public XWPFHyperlink[] getHyperlinks() { return hyperlinks.toArray( new XWPFHyperlink[hyperlinks.size()] --- src/ooxml/java/org/apache/poi/xwpf/model/XWPFHyperlinkDecorator.java (revision 793891) +++ src/ooxml/java/org/apache/poi/xwpf/model/XWPFHyperlinkDecorator.java (working copy) @@ -19,7 +19,7 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHyperlink; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText; -import org.apache.poi.xwpf.usermodel.XWPFParagraph;; +import org.apache.poi.xwpf.usermodel.XWPFParagraph; /** * Decorator class for XWPFParagraph allowing to add hyperlinks --- src/ooxml/testcases/org/apache/poi/xwpf/extractor/TestXWPFWordExtractor.java (revision 793891) +++ src/ooxml/testcases/org/apache/poi/xwpf/extractor/TestXWPFWordExtractor.java (working copy) @@ -54,6 +54,12 @@ private XWPFDocument xmlE; private File fileE; + /** + * File with footnotes + */ + private XWPFDocument xmlFootnotes; + private File fileFootnotes; + protected void setUp() throws Exception { super.setUp(); @@ -77,17 +83,24 @@ System.getProperty("HWPF.testdata.path") + File.separator + "TestDocument.docx" ); + fileFootnotes = new File( + System.getProperty("HWPF.testdata.path") + + File.separator + "snoska.docx" + ); + assertTrue(fileA.exists()); assertTrue(fileB.exists()); assertTrue(fileC.exists()); assertTrue(fileD.exists()); assertTrue(fileE.exists()); - + assertTrue(fileFootnotes.exists()); + xmlA = new XWPFDocument(POIXMLDocument.openPackage(fileA.toString())); xmlB = new XWPFDocument(POIXMLDocument.openPackage(fileB.toString())); xmlC = new XWPFDocument(POIXMLDocument.openPackage(fileC.toString())); xmlD = new XWPFDocument(POIXMLDocument.openPackage(fileD.toString())); xmlE = new XWPFDocument(POIXMLDocument.openPackage(fileE.toString())); + xmlFootnotes = new XWPFDocument(POIXMLDocument.openPackage(fileFootnotes.toString())); } /** @@ -225,4 +238,12 @@ extractor.getText() ); } + + public void testFootnotes() throws Exception { + XWPFWordExtractor extractor = + new XWPFWordExtractor(xmlFootnotes); + extractor.getText(); + + assertTrue(extractor.getText().contains("snoska")); + } }