Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bookmark bug fix #27

Merged
merged 5 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DocxTemplater.Images/DocxTemplater.Images.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
<PackageReference Include="SixLabors.ImageSharp" Version="[3.1.5,4.0.0)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DocxTemplater\DocxTemplater.csproj" />
Expand Down
2 changes: 1 addition & 1 deletion DocxTemplater.Markdown/DocxTemplater.Markdown.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Markdig" Version="0.37.0" />
<PackageReference Include="Markdig" Version="[0.37.0,1.0.0)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DocxTemplater\DocxTemplater.csproj" />
Expand Down
55 changes: 55 additions & 0 deletions DocxTemplater.Test/BookmarkInDifferentTableRowDoesNotcauseCrash.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;

namespace DocxTemplater.Test
{
internal class BookmarkInDifferentTableRowDoesNotcauseCrash
{
[Test]
public void Test()
{
string content = @"<w:p xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"">
<w:r>
<w:t xml:space=""preserve"">This is sentence one.</w:t>
</w:r>
<w:bookmarkStart w:id=""0"" w:name=""testing123""/>
<w:r>
<w:t>This is sentence two. {{.}}</w:t>
</w:r>
</w:p>
<w:p xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"">
<w:r>
<w:t xml:space=""preserve"">This </w:t>
</w:r>
<w:bookmarkEnd w:id=""0""/>
<w:r>
<w:t>is sentence three.{{.}}</w:t>
</w:r>
</w:p>";

using var memStream = new MemoryStream();
using var wpDocument = WordprocessingDocument.Create(memStream, WordprocessingDocumentType.Document);
var mainPart = wpDocument.AddMainDocumentPart();
mainPart.Document = new Document
{
Body = new Body
{
InnerXml = content
}
};
wpDocument.Save();
memStream.Position = 0;
var docTemplate = new DocxTemplate(memStream);
docTemplate.BindModel("ds", "hi there");
var result = docTemplate.Process();
docTemplate.Validate();

// get body
var document = WordprocessingDocument.Open(result, false);
var body = document.MainDocumentPart.Document.Body;
Assert.That(body.Descendants<BookmarkEnd>().Count(), Is.EqualTo(0));
Assert.That(body.Descendants<BookmarkStart>().Count(), Is.EqualTo(0));
}
}
}
3 changes: 2 additions & 1 deletion DocxTemplater.Test/DocxTemplater.Test.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>12.0</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
Expand Down
3 changes: 3 additions & 0 deletions DocxTemplater.Test/PatternMatcherTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ static IEnumerable TestPatternMatch_Cases()
yield return new TestCaseData("{{var}:format(a,b)}").Returns(new[] { PatternType.Variable }).SetName("Multiple Arguments");
yield return new TestCaseData("{{/}}").Returns(new[] { PatternType.ConditionEnd });
yield return new TestCaseData("{ { / } }").Returns(new[] { PatternType.ConditionEnd });
yield return new TestCaseData("{?{ds.QrBills.idx == 2}}").Returns(new[] { PatternType.Condition });
yield return new TestCaseData("{?{ds.QrBills._Idx == 2}}").Returns(new[] { PatternType.Condition }).SetName("underscore in variable name");
yield return new TestCaseData("{?{ds.QrBills._Idx % 2 == 0}}").Returns(new[] { PatternType.Condition }).SetName("modulo in condition");
yield return new TestCaseData(
"NumericValue is greater than 0 - {{ds.Items.InnerCollection.InnerValue}:toupper()}{{else}}" +
"I'm here if if this is not the case{{/}}{{/ds.Items.InnerCollection}}{{/Items}}")
Expand Down
63 changes: 63 additions & 0 deletions DocxTemplater.Test/SpecialCollectionVariableTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml;

namespace DocxTemplater.Test
{
internal class SpecialCollectionVariableTest
{
[Test]
public void TestIndexVariableInLoop()
{
var model = new[] { "Item1", "Item2", "Item3", "Item4" };
var template = "Items:{{#Items}}{{Items._Idx}}{{.}} {{/Items}}";

using var memStream = new MemoryStream();
using var wpDocument = WordprocessingDocument.Create(memStream, WordprocessingDocumentType.Document);
MainDocumentPart mainPart = wpDocument.AddMainDocumentPart();
mainPart.Document = new Document(new Body(new Paragraph(new Run(new Text(template)))));
wpDocument.Save();
memStream.Position = 0;
var docTemplate = new DocxTemplate(memStream);
docTemplate.BindModel("Items", model);
var result = docTemplate.Process();
result.Position = 0;
// compare body
result.Position = 0;
var document = WordprocessingDocument.Open(result, false);
var body = document.MainDocumentPart.Document.Body;
Assert.That(body.InnerXml, Is.EqualTo("<w:p xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">" +
"<w:r>" +
"<w:t xml:space=\"preserve\">Items:</w:t><w:t xml:space=\"preserve\">1</w:t><w:t xml:space=\"preserve\">Item1</w:t>" +
"<w:t xml:space=\"preserve\"> </w:t><w:t xml:space=\"preserve\">2</w:t><w:t xml:space=\"preserve\">Item2</w:t>" +
"<w:t xml:space=\"preserve\"> </w:t><w:t xml:space=\"preserve\">3</w:t><w:t xml:space=\"preserve\">Item3</w:t>" +
"<w:t xml:space=\"preserve\"> </w:t><w:t xml:space=\"preserve\">4</w:t><w:t xml:space=\"preserve\">Item4</w:t>" +
"<w:t xml:space=\"preserve\"> </w:t></w:r></w:p>"));
}

[Test]
public void TestConditionWithIndexVariableInLoop()
{
var model = new[] { "Item1", "Item2", "Item3", "Item4" };
var template = "Items:{{#Items}}{?{Items._Idx % 2 == 0}}{{.}}{{/}}{{/Items}}";

using var memStream = new MemoryStream();
using var wpDocument = WordprocessingDocument.Create(memStream, WordprocessingDocumentType.Document);
MainDocumentPart mainPart = wpDocument.AddMainDocumentPart();
mainPart.Document = new Document(new Body(new Paragraph(new Run(new Text(template)))));
wpDocument.Save();
memStream.Position = 0;
var docTemplate = new DocxTemplate(memStream);
docTemplate.BindModel("Items", model);
var result = docTemplate.Process();
result.Position = 0;
// compare body
result.Position = 0;
var document = WordprocessingDocument.Open(result, false);
var body = document.MainDocumentPart.Document.Body;
Assert.That(body.InnerXml, Is.EqualTo("<w:p xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"><w:r><w:t xml:space=\"preserve\">Items:" +
"</w:t><w:t xml:space=\"preserve\">Item2</w:t>" +
"<w:t xml:space=\"preserve\">Item4</w:t></w:r></w:p>"));
}
}
}
4 changes: 2 additions & 2 deletions DocxTemplater/DocxTemplater.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="3.1.0" />
<PackageReference Include="DynamicExpresso.Core" Version="2.16.1" />
<PackageReference Include="DocumentFormat.OpenXml" Version="[3.1.0,4.0.0)" />
<PackageReference Include="DynamicExpresso.Core" Version="[2.16.1,3.0.0)" />
<PackageReference Include="GitVersion.MsBuild" Version="5.12.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
8 changes: 7 additions & 1 deletion DocxTemplater/OpenXmlHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public static OpenXmlElement ElementBeforeInDocument<TElement>(this OpenXmlEleme
return null;
}

public static OpenXmlElement ElementAfterInDocument<TElement>(this OpenXmlElement element)
public static TElement ElementAfterInDocument<TElement>(this OpenXmlElement element)
where TElement : OpenXmlElement
{
var parent = element.Parent;
Expand Down Expand Up @@ -509,6 +509,11 @@ public static int CmToEmu(int centimeter)
return centimeter * 360000;
}

public static int MmToEmu(int millimeter)
{
return millimeter * 36000;
}

public static int PixelsToEmu(int pixels)
{
return pixels * 9525;
Expand All @@ -525,6 +530,7 @@ public static int LengthToEmu(int value, string unit)
return unit switch
{
"cm" => CmToEmu(value),
"mm" => MmToEmu(value),
"px" => PixelsToEmu(value),
"in" => InchToEmu(value),
_ => throw new ArgumentException("Unsupported unit: " + unit)
Expand Down
2 changes: 1 addition & 1 deletion DocxTemplater/PatterMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ internal static class PatternMatcher
(?<separator>:\s*s\s*:) |
(?<else>(?:else)|:) |
(?(condMarker) # if condition marker is set, we expect a condition
(?<condition>[a-zA-Z0-9+\-*\/><=\s\.\!&\|]+)? #condition name (without brackets)
(?<condition>[a-zA-Z0-9+\-*\/><=\s\.\!&\|_%]+)? #condition expression (without brackets)
|
(?:
(?<prefix>[\/\#])?(?<varname>[a-zA-Z0-9\._]+)? #variable name
Expand Down
16 changes: 10 additions & 6 deletions DocxTemplater/TemplateProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,16 +106,20 @@ private static void Cleanup(OpenXmlCompositeElement element, bool removeEmptyEle
}
}

// make all Bookmark ids unique
uint id = 0;
foreach (var bookmarkStart in element.Descendants<BookmarkStart>())
// remove all bookmarks -> not useful for generated documents and complex to handle
// because of special cases in tables see
// https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.bookmarkstart?view=openxml-3.0.1#remarks
foreach (var bookmark in element.Descendants<BookmarkStart>().ToList())
{
bookmarkStart.Id = $"{id++}";
bookmarkStart.NextSibling<BookmarkEnd>().Id = bookmarkStart.Id;
bookmark.RemoveWithEmptyParent();
}
foreach (var bookmark in element.Descendants<BookmarkEnd>().ToList())
{
bookmark.RemoveWithEmptyParent();
}

// make dock properties ids unique
id = 1;
uint id = 1;
var dockProperties = element.Descendants<DocProperties>().ToList();
var existingIds = new HashSet<uint>(dockProperties.Select(x => x.Id.Value).ToList());
foreach (var docPropertiesWithSameId in dockProperties.GroupBy(x => x.Id).Where(x => x.Count() > 1))
Expand Down
Loading
Loading