petefc wrote:We are periodically getting files that error when we try to process them due to missing list references.
The error message is like :"message": "0 level missing for abstractListDefinition 5"
This happens in class ListNumberingDefinition; an override is trying to override a list level for which there is no definition.
Do you happen to know whether the documents in question were created in Word, or some other way?
Could you please post the contents of the relevant abstractListDefinition?
For cleaning up unused lists, you could try:
Using java Syntax Highlighting
package org.docx4j.samples;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.docx4j.Docx4J;
import org.docx4j.TraversalUtil;
import org.docx4j.TraversalUtil.CallbackImpl;
import org.docx4j.jaxb.Context;
import org.docx4j.model.styles.Node;
import org.docx4j.model.styles.StyleTree;
import org.docx4j.model.styles.StyleTree.AugmentedStyle;
import org.docx4j.model.styles.Tree;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.Filetype;
import org.docx4j.openpackaging.packages.OpcPackage;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.Part;
import org.docx4j.openpackaging.parts.WordprocessingML.FooterPart;
import org.docx4j.openpackaging.parts.WordprocessingML.HeaderPart;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.openpackaging.parts.relationships.RelationshipsPart;
import org.docx4j.relationships.Relationship;
import org.docx4j.wml.Body;
import org.docx4j.wml.CTEndnotes;
import org.docx4j.wml.CTFootnotes;
import org.docx4j.wml.Comments;
import org.docx4j.wml.Ftr;
import org.docx4j.wml.Hdr;
import org.docx4j.wml.Numbering;
import org.docx4j.wml.Numbering.AbstractNum;
import org.docx4j.wml.Numbering.Num;
import org.docx4j.wml.P;
import org.docx4j.wml.PPr;
import org.docx4j.wml.PPrBase.NumPr;
import org.docx4j.wml.Style;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Remove unused numbering from an output docx
* (TODO: this version removes it even if it is used in an unused style)
*/
public class RemoveUnusedNumbering
{
protected static Logger log
= LoggerFactory.
getLogger(RemoveUnusedNumbering.
class);
public static void main
(String[] args
) throws Docx4JException
{
WordprocessingMLPackage
opcPackage = (WordprocessingMLPackage
)OpcPackage.
load(
new java.
io.
File(
System.
getProperty("user.dir")+ "/OUT_MergeWholeDocumentsIncremental.docx"), Filetype.
ZippedPackage);
RemoveUnusedNumbering trimmer
= new RemoveUnusedNumbering
();
trimmer.
trim(opcPackage
);
// Result?
System.
out.
println(opcPackage.
getMainDocumentPart().
getNumberingDefinitionsPart().
getXML());
Docx4J.
save(opcPackage,
new java.
io.
File(
System.
getProperty("user.dir")+ "/OUT_MergeWholeDocumentsIncremental_reduced.docx"));
}
public void trim
(WordprocessingMLPackage opcPackage
) throws Docx4JException
{
Numbering nIn
= opcPackage.
getMainDocumentPart().
getNumberingDefinitionsPart().
getContents();
// Find which styles are used in the docx, across 4 parts
//Set<String> stylesInUse = opcPackage.getMainDocumentPart().getStylesInUse();
StyleTree styleTree
= opcPackage.
getMainDocumentPart().
getStyleTree();
Tree
<AugmentedStyle
> paragraphStylesTree
= styleTree.
getParagraphStylesTree();
// Find which numbers are used in the docx,
// directly or via styles
Set
<BigInteger
> numId
= new HashSet
<BigInteger
>();
// .. via styles
walk
(paragraphStylesTree.
getRootElement(), numId
);
// .. directly
getNumberingInUse
(opcPackage.
getMainDocumentPart(), numId
);
// Remove unused numbering
deleteUnusedNumbering
(opcPackage, numId
);
}
private static void deleteUnusedNumbering
(WordprocessingMLPackage output, Set
<BigInteger
> usedNumId
) throws Docx4JException
{
Numbering nIn
= output.
getMainDocumentPart().
getNumberingDefinitionsPart().
getContents();
System.
out.
println("BEFORE");
System.
out.
println("AbsNum: " + nIn.
getAbstractNum().
size());
System.
out.
println("Num: " + nIn.
getNum().
size());
System.
out.
println("keeping: " + usedNumId.
size());
Numbering nOut
= Context.
getWmlObjectFactory().
createNumbering();
HashMap
<BigInteger, AbstractNum
> abstracts
= new HashMap
<BigInteger, AbstractNum
>();
for (AbstractNum abstractNum
: nIn.
getAbstractNum()) {
abstracts.
put(abstractNum.
getAbstractNumId(), abstractNum
);
}
Set
<BigInteger
> usedAbstracts
= new HashSet
<BigInteger
>();
// Copy used Num entries to nOut
for(Num num
: nIn.
getNum()) {
if (usedNumId.
contains(num.
getNumId())) {
// retain
log.
debug("Keeping NumId " + num.
getNumId());
nOut.
getNum().
add(num
);
usedAbstracts.
add(num.
getAbstractNumId().
getVal());
}
}
// Copy used abstractNum entries to nOut
for (BigInteger n
: usedAbstracts
) {
log.
debug("Keeping abstractNum " + n
);
nOut.
getAbstractNum().
add(abstracts.
get(n
));
}
System.
out.
println("AFTER");
System.
out.
println("Num: " + nOut.
getNum().
size());
System.
out.
println("AbsNum: " + nOut.
getAbstractNum().
size());
output.
getMainDocumentPart().
getNumberingDefinitionsPart().
setContents(nOut
);
}
private <T
> void walk
(Node
<T
> element, Set
<BigInteger
> set
) {
if (element
==null) {return;}
if (element.
getData()!=null) {
StyleTree.
AugmentedStyle augmentedStyle
= (StyleTree.
AugmentedStyle)element.
getData();
Style s
= augmentedStyle.
getStyle();
if (s.
getPPr()!=null
&& s.
getPPr().
getNumPr()!=null) {
NumPr numPr
= s.
getPPr().
getNumPr();
set.
add(numPr.
getNumId().
getVal());
log.
debug("Added NumId " + numPr.
getNumId().
getVal());
} else {
log.
debug("No numbering in style " + s.
getName() + ", id " + s.
getStyleId());
}
}
for (Node
<T
> data
: element.
getChildren()) {
walk
(data, set
);
}
}
/**
* Traverse the document, and return a map of all numbering which are used
* directly in the document.
* @return
*/
public Set
<BigInteger
> getNumberingInUse
(MainDocumentPart mdp, Set
<BigInteger
> numId
){
org.
docx4j.
wml.
Document wmlDocumentEl
= (org.
docx4j.
wml.
Document)mdp.
getJaxbElement();
Body body
= wmlDocumentEl.
getBody();
List <Object
> bodyChildren
= body.
getContent();
Set
<BigInteger
> numInUse
= new HashSet
<BigInteger
>();
NumberingFinder finder
= new NumberingFinder
(numId
);
new TraversalUtil
(bodyChildren, finder
);
// Styles in headers, footers?
RelationshipsPart rp
= mdp.
getRelationshipsPart();
if (rp
!=null) {
for ( Relationship r
: rp.
getRelationships().
getRelationship() ) {
Part part
= rp.
getPart(r
);
if ( part
instanceof FooterPart
) {
Ftr ftr
= ((FooterPart
)part
).
getJaxbElement();
finder.
walkJAXBElements(ftr
);
} else if (part
instanceof HeaderPart
) {
Hdr hdr
= ((HeaderPart
)part
).
getJaxbElement();
finder.
walkJAXBElements(hdr
);
}
}
}
// Styles in endnotes, footnotes?
if (mdp.
getEndNotesPart()!=null) {
log.
debug("Looking at endnotes");
CTEndnotes endnotes
= mdp.
getEndNotesPart().
getJaxbElement();
finder.
walkJAXBElements(endnotes
);
}
if (mdp.
getFootnotesPart()!=null) {
log.
debug("Looking at footnotes");
CTFootnotes footnotes
= mdp.
getFootnotesPart().
getJaxbElement();
finder.
walkJAXBElements(footnotes
);
}
// Comments
if (mdp.
getCommentsPart()!=null) {
log.
debug("Looking at comments");
Comments comments
= mdp.
getCommentsPart().
getJaxbElement();
finder.
walkJAXBElements(comments
);
}
return numInUse
;
}
/**
* Traverse looking for numbering
*
*/
private static class NumberingFinder
extends CallbackImpl
{
Set
<BigInteger
> numInUse
; // by ID
NumberingFinder
(Set
<BigInteger
> numInUse
) {
this.
numInUse = numInUse
;
}
@Override
public List
<Object
> apply
(Object o
) {
if (o
instanceof org.
docx4j.
wml.
P) {
PPr pPr
= ((P
)o
).
getPPr();
if (pPr
!=null
&& pPr.
getNumPr()!=null) {
NumPr numPr
= pPr.
getNumPr();
numInUse.
add(numPr.
getNumId().
getVal());
log.
debug("Added NumId " + numPr.
getNumId().
getVal());
} else {
log.
debug("No numbering in w:p " );
}
}
return null;
}
@Override
public boolean shouldTraverse
(Object o
) {
if (o
instanceof org.
docx4j.
wml.
Br
|| o
instanceof org.
docx4j.
wml.
R.
Tab
|| o
instanceof org.
docx4j.
wml.
R.
LastRenderedPageBreak) {
return false;
}
return true;
}
}
}
Parsed in 0.034 seconds, using
GeSHi 1.0.8.4