POI-57889 prevent NPE with on some documents with XWPFParagraph's getNumFmt() and add some other classes to enable calculation of paragraph numbers
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1677723 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
5f92db369f
commit
8bfc6056c8
@ -20,7 +20,6 @@ import java.math.BigInteger;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.poi.POIXMLDocumentPart;
|
import org.apache.poi.POIXMLDocumentPart;
|
||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
import org.apache.poi.wp.usermodel.Paragraph;
|
import org.apache.poi.wp.usermodel.Paragraph;
|
||||||
@ -28,11 +27,14 @@ import org.apache.xmlbeans.XmlCursor;
|
|||||||
import org.apache.xmlbeans.XmlObject;
|
import org.apache.xmlbeans.XmlObject;
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum;
|
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum;
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder;
|
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.CTFtnEdnRef;
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHyperlink;
|
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHyperlink;
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTInd;
|
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTInd;
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTJc;
|
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTJc;
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLvl;
|
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.CTOnOff;
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
|
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
|
||||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPBdr;
|
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPBdr;
|
||||||
@ -284,13 +286,97 @@ public class XWPFParagraph implements IBodyElement, IRunBody, ISDTContents, Para
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(level != null)
|
if(level != null && level.getNumFmt() != null
|
||||||
|
&& level.getNumFmt().getVal() != null)
|
||||||
return level.getNumFmt().getVal().toString();
|
return level.getNumFmt().getVal().toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
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
|
* setNumID of Paragraph
|
||||||
* @param numPos
|
* @param numPos
|
||||||
|
@ -26,7 +26,7 @@ import org.apache.poi.xwpf.XWPFTestDataSamples;
|
|||||||
|
|
||||||
public class TestXWPFNumbering extends TestCase {
|
public class TestXWPFNumbering extends TestCase {
|
||||||
|
|
||||||
public void testCompareAbstractNum() throws IOException{
|
public void testCompareAbstractNum() throws IOException {
|
||||||
XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("Numbering.docx");
|
XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("Numbering.docx");
|
||||||
XWPFNumbering numbering = doc.getNumbering();
|
XWPFNumbering numbering = doc.getNumbering();
|
||||||
BigInteger numId = BigInteger.valueOf(1);
|
BigInteger numId = BigInteger.valueOf(1);
|
||||||
@ -74,4 +74,36 @@ public class TestXWPFNumbering extends TestCase {
|
|||||||
assertEquals("lowerLetter", doc.getParagraphs().get(5).getNumFmt());
|
assertEquals("lowerLetter", doc.getParagraphs().get(5).getNumFmt());
|
||||||
assertEquals("lowerRoman", doc.getParagraphs().get(6).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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user