DocX
DocX copied to clipboard
HeadingType is not applied when using Load()
While below code is powershell it uses your .NET. Essentially when you use .Load(Path) and apply HeaderStyle it's not saved in final document making TOC useless. It behaves as expected on .Create(Path)
Import-Module PSWriteWord -Force
$FilePath = "$Env:USERPROFILE\Desktop\PSWriteWord-Example-TableOfContent3.docx"
$WordDocument = New-WordDocument -FilePath $FilePath
$Toc = Add-WordTOC -WordDocument $WordDocument -Title 'Table of content' -HeaderStyle Heading2
Add-WordSection -WordDocument $WordDocument -PageBreak
Add-WordText -WordDocument $WordDocument -Text 'This is my first title' -HeadingType Heading1
Add-WordSection -WordDocument $WordDocument -PageBreak
Add-WordText -WordDocument $WordDocument -Text 'This is my second title' -HeadingType Heading1 -Color Red -CapsStyle caps
Add-WordSection -WordDocument $WordDocument -PageBreak
Add-WordText -WordDocument $WordDocument -Text 'This is my third title' -HeadingType Heading2 -Italic $true -Bold $true
Save-WordDocument $WordDocument
### Start Word with file
Invoke-Item $FilePath
Import-Module PSWriteWord -Force
$FilePath = "$Env:USERPROFILE\Desktop\PSWriteWord-Example-TableOfContent7.docx"
$FilePathTemplate = "$PSScriptRoot\Templates\WordTemplate.docx"
$WordDocument = Get-WordDocument -FilePath $FilePathTemplate
$Toc = Add-WordTOC -WordDocument $WordDocument -Title 'Table of content' -HeaderStyle Heading2
Add-WordSection -WordDocument $WordDocument -PageBreak
Add-WordText -WordDocument $WordDocument -Text 'This is my first title' -HeadingType Heading1
Add-WordSection -WordDocument $WordDocument -PageBreak
Add-WordText -WordDocument $WordDocument -Text 'This is my second title' -HeadingType Heading1 -Color Red -CapsStyle caps
Add-WordSection -WordDocument $WordDocument -PageBreak
Add-WordText -WordDocument $WordDocument -Text 'This is my third title' -HeadingType Heading2 -Italic $true -Bold $true
$WordDocument.Xml
Save-WordDocument $WordDocument -FilePath $FilePath
### Start Word with file
Invoke-Item $FilePath
To reproduce it in pseudo code
Load
Create few Paragraphs
Add text to each paragraph
Make it Heading1 or Heading2
Save
Open
When checking:
Document.Paragraphs.StyleName
Heading2
TOC1
Normal
Normal
Heading1
Normal
Heading1
Normal
Heading2
Normal
Heading2
TOC1
Normal
Normal
Heading1
Normal
Heading1
Normal
Heading2
So comparison is almost identical but still save doesn't cover this. Replacing Load with Create - everything works again. I'm using https://github.com/EvotecIT/PSWriteWord/blob/master/Examples/Templates/WordTemplate.docx as a template but shouldn't really matter I guess.
Hi,
We cannot reproduce this in v1.2. Here's the sample we use : ` var doc = DocX.Load( "WordTemplate.docx" ); doc.InsertParagraph( "Paragraph2" ).Heading( HeadingType.Heading1 ); doc.InsertParagraph( "Paragraph3" ).Heading( HeadingType.Heading2 ); doc.SaveAs("output.docx");
var doc2 = DocX.Load( "output.docx" );
var paragraphCount = doc2.Paragraphs.Count;
Debug.Assert( doc2.Paragraphs[ paragraphCount - 1 ].StyleName == HeadingType.Heading2.ToString() );
Debug.Assert( doc2.Paragraphs[ paragraphCount - 2 ].StyleName == HeadingType.Heading1.ToString() );`
Are we missing anything ? Thank you.
Yes. I use $Paragraph.StyleName = $HeadingType instead of the way you do. I guess I'll switch to your approach if it works. So in C# it would be
var doc = DocX.Load( "WordTemplate.docx" );
doc.InsertParagraph( "Paragraph2" ).StyleName = HeadingType.Heading1;
doc.InsertParagraph( "Paragraph3" ).StyleName = HeadingType.Heading2;
doc.SaveAs("output.docx");
More or less. And what I actually do in code is
var doc = DocX.Load( "WordTemplate.docx" );
var paragraph = doc.InsertParagraph( "Paragraph2" );
var paragraph1 = doc.InsertParagraph( "Paragraph3" );
paragraph.StyleName = HeadingType.Heading2;
paragraph1.StyleName = HeadingType.Heading1;
doc.SaveAs("output.docx");
And maybe I'm using it wrong but I don't see... Heading property for Paragraph

But I do see it in examples
public static void Heading()
{
Console.WriteLine( "\tHeading()" );
// Create a document.
using( DocX document = DocX.Create( ParagraphSample.ParagraphSampleOutputDirectory + @"Heading.docx" ) )
{
// Add a title.
document.InsertParagraph( "Heading types" ).FontSize( 15d ).SpacingAfter( 50d ).Alignment = Alignment.center;
var headingTypes = Enum.GetValues( typeof( HeadingType ) );
foreach( HeadingType heading in headingTypes )
{
// Set a text containing the current Heading type.
var text = string.Format( "This Paragraph is using \"{0}\" heading type.", heading.EnumDescription() );
// Add a paragraph.
var p = document.InsertParagraph().AppendLine( text );
// Set the paragraph's heading type.
p.Heading( heading );
}
document.Save();
Console.WriteLine( "\tCreated: Heading.docx\n" );
}
}
So I'll verify why I don't see it. Anyways I use it via StyleName instead of Heading property.
If you want to use it your way, you should use it this way :
`var doc = DocX.Load( "WordTemplate.docx" ); //doc.InsertParagraph( "Paragraph2" ).Heading( HeadingType.Heading1 ); //doc.InsertParagraph( "Paragraph3" ).Heading( HeadingType.Heading2 ); var paragraph = doc.InsertParagraph( "Paragraph2" ); var paragraph1 = doc.InsertParagraph( "Paragraph3" ); paragraph.StyleName = HeadingType.Heading1.ToString(); paragraph1.StyleName = HeadingType.Heading2.ToString(); doc.SaveAs("output.docx");
var doc2 = DocX.Load( "output.docx" );
var paragraphCount = doc2.Paragraphs.Count;
Debug.Assert( doc2.Paragraphs[ paragraphCount - 1 ].StyleName == HeadingType.Heading2.ToString() );
Debug.Assert( doc2.Paragraphs[ paragraphCount - 2 ].StyleName == HeadingType.Heading1.ToString() );`
Paragraph only contains a StyleName property, which is a string. It doesn't contain a Heading property.
Well I do have that

Yet the result is:

In c#
public static void InsertTableOfContentWithReference1()
{
Console.WriteLine("\tInsertTableOfContentWithReference()");
// Create a document.
using (DocX document = DocX.Load(TableOfContentSample.TableOfContentSampleOutputDirectory + @"WordTemplate.docx"))
{
var paragraph = document.InsertParagraph("Paragraph2");
var paragraph1 = document.InsertParagraph("Paragraph3");
paragraph.StyleName = HeadingType.Heading1.ToString();
paragraph1.StyleName = HeadingType.Heading2.ToString();
document.SaveAs(TableOfContentSample.TableOfContentSampleOutputDirectory + @"InsertTableOfContentWithReference1.docx");
Console.WriteLine("\tCreated: InsertTableOfContentWithReference.docx\n");
}
}
Notice how it's not set

And Create
public static void InsertTableOfContentWithReference1()
{
Console.WriteLine("\tInsertTableOfContentWithReference()");
// Create a document.
using (DocX document = DocX.Create(TableOfContentSample.TableOfContentSampleOutputDirectory + @"InsertTableOfContentWithReference1.docx"))
//using (DocX document = DocX.Load(TableOfContentSample.TableOfContentSampleOutputDirectory + @"WordTemplate.docx"))
{
var paragraph = document.InsertParagraph("Paragraph2");
var paragraph1 = document.InsertParagraph("Paragraph3");
paragraph.StyleName = HeadingType.Heading1.ToString();
paragraph1.StyleName = HeadingType.Heading2.ToString();
document.SaveAs(TableOfContentSample.TableOfContentSampleOutputDirectory + @"InsertTableOfContentWithReference1.docx");
Console.WriteLine("\tCreated: InsertTableOfContentWithReference.docx\n");
}
}

Diffence is just Create vs Load.
And your code doesn't give better results either:
public static void InsertTableOfContentWithReference1()
{
Console.WriteLine("\tInsertTableOfContentWithReference()");
// Create a document.
//using (DocX document = DocX.Create(TableOfContentSample.TableOfContentSampleOutputDirectory + @"InsertTableOfContentWithReference1.docx"))
using (DocX document = DocX.Load(TableOfContentSample.TableOfContentSampleOutputDirectory + @"WordTemplate.docx"))
{
var paragraph = document.InsertParagraph("Paragraph2").Heading(HeadingType.Heading1);
var paragraph1 = document.InsertParagraph("Paragraph3").Heading(HeadingType.Heading1);
// paragraph.StyleName = HeadingType.Heading1.ToString();
// paragraph1.StyleName = HeadingType.Heading2.ToString();
document.SaveAs(TableOfContentSample.TableOfContentSampleOutputDirectory + @"InsertTableOfContentWithReference1.docx");
Console.WriteLine("\tCreated: InsertTableOfContentWithReference.docx\n");
}
}
Headings are not set.
Hello, Thank you for the precision.
When creating a document, the style used will be the the default styles (including Heading1, Heading2...), but when loading a document, its defined styles will be used. In this case, WordTemplate.docx do not contains the HeadingX styles.
We will investigate on this.
Hello After investigations, I come to the same conclusion as Klys. Anyway thanks for the great job done, & I am looking forward for the fix.
I worked around it by creating empty doc, saving and then adding my flavors making it my template. Works
Hi @PrzemyslawKlys , i'm experiencing the same issue and would be very helpful if you can be more detailed on your solution proposal.
Thanks in advance
Just create an empty doc with DocX and work from there. It will have proper format that is required.
Just create an empty doc with DocX and work from there. It will have proper format that is required.
@PrzemyslawKlys I tried, but if i make some change on it using Office like edit the header it keep doing the same. I have to put a logo just like u show on your screenshots, but i cant find a way to put an image as a header using DocX
What I did is exactly as I said:
- Empty document with DocX (well PSWriteWord in PowerShell)
- Open it up in Word
- Go into headers, pasted an image of logo (actually it's A4 sized logo so it covers full page along with footer as 1 image.
- Saved document
- Using that document as Template for things I do in DocX (PSWriteWord to be exact)
Thanks for your replay, i followed your suggestion but i changed the editor for the Doc Drive downloading as a .docx and it worked perfectly.
I found that if you save in latest version of Word it changes the schemas from 2006 to 2015 or later in the "document.xml" and i think that's the problem, because trying with other editors they use http://schemas.openxmlformats.org/markup-compatibility/2006
Hello everybody, Is there a planned version to solve this issue ? The proposed workaround cannot be applied inmy case. Regards,
After some investigations, the property "Stylename" is a little bit confusing. It should be "Styleid", the element name in the schema is not the same thing for a style.
In my point of view, the easiest way could be to retrieve styles by alias and to apply the retrieved style id on a property named "Styleid"
Hi mastertnt, This changed is already done. In the future relase v1.8, "StyleName" is considered obsolete while "StyleId" is the new property to use. Thank you
Hi,
Thanks for the answer.
If you use StyleId, the Load function has no trouble. The difficulty is to know the correct StyleId (the aliases displayed in Word seems more natural) or i don't the way to retrieve it from the API.
Regards,
Hi, You are right, these are not easy to know. Keep in mind that styleIds don't have spaces and use Camel case. So "Heading 1" will have the styleId "Heading1", "Normal" will have styleId "Normal"....
Hi,
Thanks for the precision, i have already seen this. I use a french template and also all the special characters present in Latin1 character set are removed for example, "Référence" will have styleId "Rfrence".
For other languages (like chinese), i don't know if it is possible to infer the styleId.
Regards,
Hi,
For Heading types, you can always use the Paragraph.Heading() method, which take in parameter a HeadingType. Therefor, you don't have to use the styleId, at least for the heading types.
In v1.8, you will also have access to a static method in Document called "GetParagraphStyleIdFromStyleName" which will take in argument a styleName and return the corresponding styleId.