]> source.dussan.org Git - poi.git/commitdiff
POI-57889 prevent NPE with on some documents with XWPFParagraph's getNumFmt() and...
authorTim Allison <tallison@apache.org>
Tue, 5 May 2015 01:39:16 +0000 (01:39 +0000)
committerTim Allison <tallison@apache.org>
Tue, 5 May 2015 01:39:16 +0000 (01:39 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1677723 13f79535-47bb-0310-9956-ffa450edef68

src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java
src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFNumbering.java
test-data/document/Numbering.docx

index c98143a5aec420be47686955e938a345034c3ace..bc0ddf85a02e72c2fca51791f8a929d78e207249 100644 (file)
@@ -20,7 +20,6 @@ import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-
 import org.apache.poi.POIXMLDocumentPart;
 import org.apache.poi.util.Internal;
 import org.apache.poi.wp.usermodel.Paragraph;
@@ -28,11 +27,14 @@ import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlObject;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFtnEdnRef;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHyperlink;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTInd;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTJc;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLvl;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTNum;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTNumLvl;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPBdr;
@@ -284,13 +286,97 @@ public class XWPFParagraph implements IBodyElement, IRunBody, ISDTContents, Para
                         break;
                     }
                 }
-                if(level != null)
+                if(level != null && level.getNumFmt() != null
+                    && level.getNumFmt().getVal() != null)
                     return level.getNumFmt().getVal().toString();
             }
         }
         return null;
     }
 
+    /**
+     * Returns the text that should be used around the paragraph level numbers.
+     *
+     * @return a string (e.g. "%1.") or null if the value is not found.
+     */
+    public String getNumLevelText() {
+        BigInteger numID = getNumID();
+        XWPFNumbering numbering = document.getNumbering();
+        if(numID != null && numbering != null) {
+            XWPFNum num = numbering.getNum(numID);
+            if(num != null) {
+                BigInteger ilvl = getNumIlvl();
+                CTNum ctNum = num.getCTNum();
+                if (ctNum == null)
+                    return null;
+
+                CTDecimalNumber ctDecimalNumber = ctNum.getAbstractNumId();
+                if (ctDecimalNumber == null)
+                    return null;
+
+                BigInteger abstractNumId = ctDecimalNumber.getVal();
+                if (abstractNumId == null)
+                    return null;
+
+                XWPFAbstractNum xwpfAbstractNum = numbering.getAbstractNum(abstractNumId);
+
+                if (xwpfAbstractNum == null)
+                    return null;
+
+                CTAbstractNum anum = xwpfAbstractNum.getCTAbstractNum();
+
+                if (anum == null)
+                    return null;
+
+                CTLvl level = null;
+                for(int i = 0; i < anum.sizeOfLvlArray(); i++) {
+                    CTLvl lvl = anum.getLvlArray(i);
+                    if(lvl != null && lvl.getIlvl() != null && lvl.getIlvl().equals(ilvl)) {
+                        level = lvl;
+                        break;
+                    }
+                }
+                if(level != null && level.getLvlText() != null
+                    && level.getLvlText().getVal() != null)
+                    return level.getLvlText().getVal().toString();
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * Gets the numstartOverride for the paragraph numbering for this paragraph.
+     * @return returns the overridden start number or null if there is no override for this paragraph.
+     */
+    public BigInteger getNumStartOverride() {
+        BigInteger numID = getNumID();
+        XWPFNumbering numbering = document.getNumbering();
+        if(numID != null && numbering != null) {
+            XWPFNum num = numbering.getNum(numID);
+
+            if(num != null) {
+                CTNum ctNum = num.getCTNum();
+                if (ctNum == null) {
+                    return null;
+                }
+                BigInteger ilvl = getNumIlvl();
+                CTNumLvl level = null;
+                for(int i = 0; i < ctNum.sizeOfLvlOverrideArray(); i++) {
+                    CTNumLvl ctNumLvl = ctNum.getLvlOverrideArray(i);
+                    if(ctNumLvl != null && ctNumLvl.getIlvl() != null &&
+                        ctNumLvl.getIlvl().equals(ilvl)) {
+                        level = ctNumLvl;
+                        break;
+                    }
+                }
+                if(level != null && level.getStartOverride() != null) {
+                    return level.getStartOverride().getVal();
+                }
+            }
+        }
+        return null;
+    }
     /**
      * setNumID of Paragraph
      * @param numPos
index fce9d18e089147cd6dffe07f9b13df102043d758..2cae023cf992c37a13cb46d16a0cacd0ab781d9a 100644 (file)
@@ -26,7 +26,7 @@ import org.apache.poi.xwpf.XWPFTestDataSamples;
 
 public class TestXWPFNumbering extends TestCase {
        
-       public void testCompareAbstractNum() throws IOException{
+       public void testCompareAbstractNum() throws IOException {
                XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("Numbering.docx");
                XWPFNumbering numbering = doc.getNumbering();
                BigInteger numId = BigInteger.valueOf(1);
@@ -74,4 +74,36 @@ public class TestXWPFNumbering extends TestCase {
                assertEquals("lowerLetter", doc.getParagraphs().get(5).getNumFmt());
                assertEquals("lowerRoman", doc.getParagraphs().get(6).getNumFmt());
   }
+
+       public void testLvlText() throws IOException {
+               XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("Numbering.docx");
+
+               assertEquals("%1.%2.%3.", doc.getParagraphs().get(12).getNumLevelText());
+
+               assertEquals("NEW-%1-FORMAT", doc.getParagraphs().get(14).getNumLevelText());
+
+               XWPFParagraph p = doc.getParagraphs().get(18);
+               assertEquals("%1.", p.getNumLevelText());
+               //test that null doesn't throw NPE
+               assertNull(p.getNumFmt());
+       }
+
+       public void testOverrideList() throws IOException {
+               //TODO: for now the try/catch block ensures loading/inclusion of CTNumLevel
+               //for down stream processing.
+               //Ideally, we should find files that actually use overrides and test against those.
+               //Use XWPFParagraph's getNumStartOverride() in the actual tests
+
+               XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("Numbering.docx");
+               XWPFParagraph p = doc.getParagraphs().get(18);XWPFNumbering numbering = doc.getNumbering();
+               boolean ex = false;
+               assertNull(p.getNumStartOverride());
+               try {
+                       numbering.getNum(p.getNumID()).getCTNum().getLvlOverrideArray(1);
+               } catch (IndexOutOfBoundsException e) {
+                       ex = true;
+               }
+               assertTrue(ex);
+       }
+
 }
index da0f32572f358d815dd3dbd89505b6485e16a6a1..d5605c9f7861be2e225c74eec41c68012a233ee1 100644 (file)
Binary files a/test-data/document/Numbering.docx and b/test-data/document/Numbering.docx differ