I want to generate a word file based on data from the database. The data may or may not contain html tag and i handle this. so, when it detects the "ul" or "ol" tag it should be list. for "ul" tag i have no issue, but for "ol" tag, the numbers in the list continue in different cells in my table generated. Can someone help me fix this.
I checked my format after generating the file by changing the extension to .zip to view document.xml and numbering.xml.
Here in my numbering.xml, my numbered list defined like this:
<w:abstractNum w:abstractNumId="2">
<w:lvl w:ilvl="0">
<w:start w:val="1"/>
<w:numFmt w:val="decimal"/>
<w:lvlText w:val="%1."/>
<w:numRestart w:val="eachSect"/>
<w:pPr>
<w:ind w:left="360" w:hanging="360"/>
</w:pPr>
</w:lvl>
</w:abstractNum>
and i have map the numId to the list:
<w:num w:numId="7">
<w:abstractNumId w:val="2"/>
</w:num>
<w:num w:numId="8">
<w:abstractNumId w:val="2"/>
</w:num>
for my document.xml:
in cell 1:
<w:p>
<w:pPr>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="7"/>
</w:numPr>
</w:pPr>
<w:r>
<w:t>SOME TEXT</w:t>
</w:r>
</w:p>
in Cell 2 same table:
<w:p>
<w:pPr>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="8"/>
</w:numPr>
</w:pPr>
<w:r>
<w:t>SOME TEXT</w:t>
</w:r>
</w:p>
Code: Method to define number list:
private void DefineNumberingStyles(MainDocumentPart mainPart)
{
NumberingDefinitionsPart numberingPart = mainPart.NumberingDefinitionsPart ?? mainPart.AddNewPart<NumberingDefinitionsPart>();
if (numberingPart.Numbering == null)
{
numberingPart.Numbering = new Numbering();
}
Numbering numbering = numberingPart.Numbering;
// Define Bullet List
AbstractNum bulletAbstractNum = new AbstractNum(
new Level(
new NumberingFormat() { Val = NumberFormatValues.Bullet },
new LevelText() { Val = "•" }, // Bullet symbol
new ParagraphProperties(
new Indentation() { Left = "360", Hanging = "360" }
)
) { LevelIndex = 0 }
) { AbstractNumberId = 1 };
// Define Numbered List
AbstractNum numberedAbstractNum = new AbstractNum(
new Level(
new StartNumberingValue() { Val = 1 },
new NumberingFormat() { Val = NumberFormatValues.Decimal },
new LevelText() { Val = "%1." }, // Number format
new NumberingRestart() { Val = RestartNumberValues.EachSection },
new ParagraphProperties(
new Indentation() { Left = "360", Hanging = "360" }
)
) { LevelIndex = 0 }
) { AbstractNumberId = 2 };
// Assign IDs
numbering.Append(bulletAbstractNum, numberedAbstractNum);
numbering.Append(new NumberingInstance(new AbstractNumId() { Val = 1 }) { NumberID = 1 }); // Bullets
numbering.Append(new NumberingInstance(new AbstractNumId() { Val = 2 }) { NumberID = 2 }); // Numbers
}
Logic to append data into cell:
else if (node.Name == "ul" || node.Name == "ol")
{
bool isOrdered = node.Name == "ol";
//int numberingId = isOrdered ? CheckNumberListStyle(node) : CheckBulletListStyle(node); // 1 = Bullets, 2 = Numbers.
NumberingDefinitionsPart numberingPart = mainPart.NumberingDefinitionsPart ?? mainPart.AddNewPart<NumberingDefinitionsPart>();
if (numberingPart.Numbering == null)
{
numberingPart.Numbering = new Numbering();
}
Numbering numbering = numberingPart.Numbering;
if (isOrdered)
{
// Create new numbering instance
NumberingInstance numberingInstance = new NumberingInstance(
new AbstractNumId() { Val = 2 }
) { NumberID = uniqueId };
numbering.Append(numberingInstance);
} else
{
// Create new numbering instance
NumberingInstance numberingInstance = new NumberingInstance(
new AbstractNumId() { Val = 1 }
) { NumberID = uniqueId };
numbering.Append(numberingInstance);
}
var listItems = node.SelectNodes("li");
if (listItems != null)
{
foreach (HtmlNode li in listItems)
{
// ** Remove unnecessary bullets inside <li> **
HtmlNode bulletNode = li.SelectSingleNode(".//span[contains(@style, 'mso-list')]"); // Find bullet span
if (bulletNode != null)
{
bulletNode.Remove(); // Remove bullet from text extraction
}
string childText = HttpUtility.HtmlDecode(li.InnerText.Trim());
Paragraph para = new Paragraph(
new ParagraphProperties(
new NumberingProperties(
new NumberingLevelReference() { Val = 0 },
new NumberingId() { Val = uniqueId }
)
)
);
Run run = new Run();
run.AppendChild(new Text(childText));
para.AppendChild(run);
parentElement.AppendChild(para);
}
}
}
I want to generate a word file based on data from the database. The data may or may not contain html tag and i handle this. so, when it detects the "ul" or "ol" tag it should be list. for "ul" tag i have no issue, but for "ol" tag, the numbers in the list continue in different cells in my table generated. Can someone help me fix this.
I checked my format after generating the file by changing the extension to .zip to view document.xml and numbering.xml.
Here in my numbering.xml, my numbered list defined like this:
<w:abstractNum w:abstractNumId="2">
<w:lvl w:ilvl="0">
<w:start w:val="1"/>
<w:numFmt w:val="decimal"/>
<w:lvlText w:val="%1."/>
<w:numRestart w:val="eachSect"/>
<w:pPr>
<w:ind w:left="360" w:hanging="360"/>
</w:pPr>
</w:lvl>
</w:abstractNum>
and i have map the numId to the list:
<w:num w:numId="7">
<w:abstractNumId w:val="2"/>
</w:num>
<w:num w:numId="8">
<w:abstractNumId w:val="2"/>
</w:num>
for my document.xml:
in cell 1:
<w:p>
<w:pPr>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="7"/>
</w:numPr>
</w:pPr>
<w:r>
<w:t>SOME TEXT</w:t>
</w:r>
</w:p>
in Cell 2 same table:
<w:p>
<w:pPr>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="8"/>
</w:numPr>
</w:pPr>
<w:r>
<w:t>SOME TEXT</w:t>
</w:r>
</w:p>
Code: Method to define number list:
private void DefineNumberingStyles(MainDocumentPart mainPart)
{
NumberingDefinitionsPart numberingPart = mainPart.NumberingDefinitionsPart ?? mainPart.AddNewPart<NumberingDefinitionsPart>();
if (numberingPart.Numbering == null)
{
numberingPart.Numbering = new Numbering();
}
Numbering numbering = numberingPart.Numbering;
// Define Bullet List
AbstractNum bulletAbstractNum = new AbstractNum(
new Level(
new NumberingFormat() { Val = NumberFormatValues.Bullet },
new LevelText() { Val = "•" }, // Bullet symbol
new ParagraphProperties(
new Indentation() { Left = "360", Hanging = "360" }
)
) { LevelIndex = 0 }
) { AbstractNumberId = 1 };
// Define Numbered List
AbstractNum numberedAbstractNum = new AbstractNum(
new Level(
new StartNumberingValue() { Val = 1 },
new NumberingFormat() { Val = NumberFormatValues.Decimal },
new LevelText() { Val = "%1." }, // Number format
new NumberingRestart() { Val = RestartNumberValues.EachSection },
new ParagraphProperties(
new Indentation() { Left = "360", Hanging = "360" }
)
) { LevelIndex = 0 }
) { AbstractNumberId = 2 };
// Assign IDs
numbering.Append(bulletAbstractNum, numberedAbstractNum);
numbering.Append(new NumberingInstance(new AbstractNumId() { Val = 1 }) { NumberID = 1 }); // Bullets
numbering.Append(new NumberingInstance(new AbstractNumId() { Val = 2 }) { NumberID = 2 }); // Numbers
}
Logic to append data into cell:
else if (node.Name == "ul" || node.Name == "ol")
{
bool isOrdered = node.Name == "ol";
//int numberingId = isOrdered ? CheckNumberListStyle(node) : CheckBulletListStyle(node); // 1 = Bullets, 2 = Numbers.
NumberingDefinitionsPart numberingPart = mainPart.NumberingDefinitionsPart ?? mainPart.AddNewPart<NumberingDefinitionsPart>();
if (numberingPart.Numbering == null)
{
numberingPart.Numbering = new Numbering();
}
Numbering numbering = numberingPart.Numbering;
if (isOrdered)
{
// Create new numbering instance
NumberingInstance numberingInstance = new NumberingInstance(
new AbstractNumId() { Val = 2 }
) { NumberID = uniqueId };
numbering.Append(numberingInstance);
} else
{
// Create new numbering instance
NumberingInstance numberingInstance = new NumberingInstance(
new AbstractNumId() { Val = 1 }
) { NumberID = uniqueId };
numbering.Append(numberingInstance);
}
var listItems = node.SelectNodes("li");
if (listItems != null)
{
foreach (HtmlNode li in listItems)
{
// ** Remove unnecessary bullets inside <li> **
HtmlNode bulletNode = li.SelectSingleNode(".//span[contains(@style, 'mso-list')]"); // Find bullet span
if (bulletNode != null)
{
bulletNode.Remove(); // Remove bullet from text extraction
}
string childText = HttpUtility.HtmlDecode(li.InnerText.Trim());
Paragraph para = new Paragraph(
new ParagraphProperties(
new NumberingProperties(
new NumberingLevelReference() { Val = 0 },
new NumberingId() { Val = uniqueId }
)
)
);
Run run = new Run();
run.AppendChild(new Text(childText));
para.AppendChild(run);
parentElement.AppendChild(para);
}
}
}
Share
asked Mar 4 at 8:49
UnknownUnknown
741 silver badge4 bronze badges
1
- The following may be of interest: Tutorial: Learn to debug C# code using Visual Studio – It all makes cents Commented Mar 4 at 16:12
1 Answer
Reset to default 1I solved the issue by using the StartOverrideNumberingValue
class every time I create a new numbering instance. This class explicitly forces a restart when the numId
changes.
Even though I used the NumberingRestart
class when defining my list, Word still did not recognize whether the list should restart, even if the numId
was different and the abstractId
was correctly mapped to it. So StartOverrideNumberingValue
is required to explicitly tell word to restart the numbering when the numId
is changes.
Example how i do it:
// Create a new NumberingInstance
var numberingInstance = new NumberingInstance(new AbstractNumId() { Val = abstractNumId })
{
NumberID = uniqueId
};
// Append the StartOverrideNumberingValue to the numbering instance
numberingInstance.Append(new StartOverrideNumberingValue() { Val = 1 });