Przeglądaj źródła

This patch adds basic support for inserting and manipulating bookmarks inside a word file. It also allows for inserting text at bookmark locations. The change was predicated on a need to insert text at bookmark locations in a sort of token replacement.

Patch provided by Simon Timms
master
MadBoy_cp 12 lat temu
rodzic
commit
af00f7ad93
6 zmienionych plików z 241 dodań i 143 usunięć
  1. 31
    3
      DocX/Container.cs
  2. 2
    1
      DocX/DocX.csproj
  3. 172
    129
      DocX/Paragraph.cs
  4. 20
    0
      Examples/Program.cs
  5. 4
    4
      UnitTests/DocXUnitTests.cs
  6. 12
    6
      UnitTests/UnitTests.csproj

+ 31
- 3
DocX/Container.cs Wyświetl plik

using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Packaging;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions;
using System.Xml.Linq; using System.Xml.Linq;
using System.IO.Packaging;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace Novacode namespace Novacode
{ {
p.ReplaceText(oldValue, newValue, trackChanges, options, newFormatting, matchFormatting, fo); p.ReplaceText(oldValue, newValue, trackChanges, options, newFormatting, matchFormatting, fo);
} }
public virtual void InsertAtBookmark(string toInsert, string bookmarkName)
{
if (String.IsNullOrWhiteSpace(bookmarkName))
throw new ArgumentException("bookmark cannot be null or empty", "bookmarkName");
var headerCollection = Document.Headers;
var headers = new List<Header> { headerCollection.first, headerCollection.even, headerCollection.odd };
foreach (var header in headers.Where(x => x != null))
foreach (var paragraph in header.Paragraphs)
paragraph.InsertAtBookmark(toInsert, bookmarkName);
foreach (var paragraph in Paragraphs)
paragraph.InsertAtBookmark(toInsert, bookmarkName);
var footerCollection = Document.Footers;
var footers = new List<Footer> { footerCollection.first, footerCollection.even, footerCollection.odd };
foreach (var footer in footers.Where(x => x != null))
foreach (var paragraph in footer.Paragraphs)
paragraph.InsertAtBookmark(toInsert, bookmarkName);
}
public virtual Paragraph InsertParagraph(int index, string text, bool trackChanges) public virtual Paragraph InsertParagraph(int index, string text, bool trackChanges)
{ {
return InsertParagraph(index, text, trackChanges, null); return InsertParagraph(index, text, trackChanges, null);
return p; return p;
} }
public virtual Paragraph InsertBookmark(String bookmarkName)
{
var p = InsertParagraph();
p.AppendBookmark(bookmarkName);
return p;
}
public virtual Table InsertTable(int rowCount, int columnCount) //Dmitchern, changed to virtual, and overrided in Table.Cell public virtual Table InsertTable(int rowCount, int columnCount) //Dmitchern, changed to virtual, and overrided in Table.Cell
{ {
XElement newTable = HelperFunctions.CreateTable(rowCount, columnCount); XElement newTable = HelperFunctions.CreateTable(rowCount, columnCount);

+ 2
- 1
DocX/DocX.csproj Wyświetl plik

<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Novacode</RootNamespace> <RootNamespace>Novacode</RootNamespace>
<AssemblyName>DocX</AssemblyName> <AssemblyName>DocX</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<SccProjectName>SAK</SccProjectName> <SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath> <SccLocalPath>SAK</SccLocalPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Bookmark.cs" />
<Compile Include="Border.cs" /> <Compile Include="Border.cs" />
<Compile Include="Charts\Axis.cs" /> <Compile Include="Charts\Axis.cs" />
<Compile Include="Charts\BarChart.cs" /> <Compile Include="Charts\BarChart.cs" />

+ 172
- 129
DocX/Paragraph.cs Wyświetl plik

using System; using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO; using System.IO;
using System.IO.Packaging;
using System.Linq; using System.Linq;
using System.Drawing;
using System.Xml.Linq;
using System.Collections;
using System.IO.Packaging;
using System.Globalization;
using System.Security.Principal; using System.Security.Principal;
using System.Collections.Generic;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Xml.Linq;
namespace Novacode namespace Novacode
{ {
get get
{ {
return ParagraphNumberPropertiesBacker ?? (ParagraphNumberPropertiesBacker = GetParagraphNumberProperties());
return ParagraphNumberPropertiesBacker ?? (ParagraphNumberPropertiesBacker = GetParagraphNumberProperties());
} }
} }
private XElement GetParagraphNumberProperties()
{
var numPrNode = Xml.Descendants().FirstOrDefault(el => el.Name.LocalName == "numPr");
if (numPrNode != null)
private XElement GetParagraphNumberProperties()
{ {
var numIdNode = numPrNode.Descendants().First(numId => numId.Name.LocalName == "numId");
var numIdAttribute = numIdNode.Attribute(DocX.w + "val");
if (numIdAttribute != null && numIdAttribute.Value.Equals("0"))
{
return null;
}
}
var numPrNode = Xml.Descendants().FirstOrDefault(el => el.Name.LocalName == "numPr");
if (numPrNode != null)
{
var numIdNode = numPrNode.Descendants().First(numId => numId.Name.LocalName == "numId");
var numIdAttribute = numIdNode.Attribute(DocX.w + "val");
if (numIdAttribute != null && numIdAttribute.Value.Equals("0"))
{
return null;
}
}
return numPrNode;
}
return numPrNode;
}
private bool? IsListItemBacker { get; set; } private bool? IsListItemBacker { get; set; }
/// <summary> /// <summary>
{ {
// Convert the path of this mainPart to its equilivant rels file path. // Convert the path of this mainPart to its equilivant rels file path.
string path = mainPart.Uri.OriginalString.Replace("/word/", ""); string path = mainPart.Uri.OriginalString.Replace("/word/", "");
Uri rels_path = new Uri("/word/_rels/" + path + ".rels", UriKind.Relative);
Uri rels_path = new Uri(String.Format("/word/_rels/{0}.rels", path), UriKind.Relative);
// Check to see if the rels file exists and create it if not. // Check to see if the rels file exists and create it if not.
if (!Document.package.PartExists(rels_path)) if (!Document.package.PartExists(rels_path))
// Returns the underlying XElement's Value property. // Returns the underlying XElement's Value property.
get get
{ {
try
{
return HelperFunctions.GetFormattedText(Xml);
}
catch (Exception)
{
return null;
}
try
{
return HelperFunctions.GetFormattedText(Xml);
}
catch (Exception)
{
return null;
}
} }
} }
return this; return this;
} }
public Paragraph AppendBookmark(String bookmarkName)
{
XElement wBookmarkStart = new XElement(
XName.Get("bookmarkStart", DocX.w.NamespaceName),
new XAttribute(XName.Get("id", DocX.w.NamespaceName), 0),
new XAttribute(XName.Get("name", DocX.w.NamespaceName), bookmarkName));
Xml.Add(wBookmarkStart);
XElement wBookmarkEnd = new XElement(
XName.Get("bookmarkEnd", DocX.w.NamespaceName),
new XAttribute(XName.Get("id", DocX.w.NamespaceName), 0),
new XAttribute(XName.Get("name", DocX.w.NamespaceName), bookmarkName));
Xml.Add(wBookmarkEnd);
return this;
}
public IEnumerable<Bookmark> GetBookmarks()
{
return Xml.Descendants(XName.Get("bookmarkStart", DocX.w.NamespaceName))
.Select(x => x.Attribute(XName.Get("name", DocX.w.NamespaceName)))
.Select(x => new Bookmark
{
Name = x.Value,
Paragraph = this
});
}
public void InsertAtBookmark(string toInsert, string bookmarkName)
{
var bookmark = Xml.Descendants(XName.Get("bookmarkStart", DocX.w.NamespaceName))
.Where(x => x.Attribute(XName.Get("name", DocX.w.NamespaceName)).Value == bookmarkName).SingleOrDefault();
if (bookmark != null)
{
var run = HelperFunctions.FormatInput(toInsert, null);
bookmark.AddBeforeSelf(run);
runs = Xml.Elements(XName.Get("r", DocX.w.NamespaceName)).ToList();
HelperFunctions.RenumberIDs(Document);
}
}
internal string GetOrGenerateRel(Picture p) internal string GetOrGenerateRel(Picture p)
{ {
string image_uri_string = p.img.pr.TargetUri.OriginalString; string image_uri_string = p.img.pr.TargetUri.OriginalString;
p_xml = (XElement)run.Xml.NextNode; p_xml = (XElement)run.Xml.NextNode;
} }
} }
// Extract the attribute id from the Pictures Xml.
XAttribute a_id =
(
from e in p_xml.Descendants()
where e.Name.LocalName.Equals("blip")
select e.Attribute(XName.Get("embed", "http://schemas.openxmlformats.org/officeDocument/2006/relationships"))
).Single();
// Extract the attribute id from the Pictures Xml.
XAttribute a_id =
(
from e in p_xml.Descendants()
where e.Name.LocalName.Equals("blip")
select e.Attribute(XName.Get("embed", "http://schemas.openxmlformats.org/officeDocument/2006/relationships"))
).Single();
// Set its value to the Pictures relationships id.
a_id.SetValue(Id);
// Set its value to the Pictures relationships id.
a_id.SetValue(Id);
return this; return this;
} }
return; return;
} }
var contentIsListOfFontProperties = false;
var fontProps = content as IEnumerable;
if (fontProps != null)
{
foreach (object property in fontProps)
var contentIsListOfFontProperties = false;
var fontProps = content as IEnumerable;
if (fontProps != null)
{ {
contentIsListOfFontProperties = (property as XAttribute != null);
foreach (object property in fontProps)
{
contentIsListOfFontProperties = (property as XAttribute != null);
}
} }
}
foreach (XElement run in runs) foreach (XElement run in runs)
{ {
rPr.SetElementValue(textFormatPropName, value); rPr.SetElementValue(textFormatPropName, value);
XElement last = rPr.Elements().Last(); XElement last = rPr.Elements().Last();
if (contentIsListOfFontProperties) //if content is a list of attributes, as in the case when specifying a font family
{
foreach (object property in fontProps)
if (contentIsListOfFontProperties) //if content is a list of attributes, as in the case when specifying a font family
{ {
if (last.Attribute(((System.Xml.Linq.XAttribute) (property)).Name) == null)
{
last.Add(property); //Add this attribute if element doesn't have it
}
else
{
last.Attribute(((System.Xml.Linq.XAttribute) (property)).Name).Value =
((System.Xml.Linq.XAttribute) (property)).Value; //Apply value only if element already has it
}
foreach (object property in fontProps)
{
if (last.Attribute(((System.Xml.Linq.XAttribute)(property)).Name) == null)
{
last.Add(property); //Add this attribute if element doesn't have it
}
else
{
last.Attribute(((System.Xml.Linq.XAttribute)(property)).Name).Value =
((System.Xml.Linq.XAttribute)(property)).Value; //Apply value only if element already has it
}
}
} }
}
if (content as System.Xml.Linq.XAttribute != null)//If content is an attribute if (content as System.Xml.Linq.XAttribute != null)//If content is an attribute
{ {
} }
} }
/// <summary> /// <summary>
/// Set the linespacing for this paragraph manually. /// Set the linespacing for this paragraph manually.
/// </summary> /// </summary>
public void SetLineSpacing(LineSpacingType spacingType, float spacingFloat) public void SetLineSpacing(LineSpacingType spacingType, float spacingFloat)
{ {
spacingFloat = spacingFloat * 240; spacingFloat = spacingFloat * 240;
int spacingValue = (int) spacingFloat;
int spacingValue = (int)spacingFloat;
var pPr = this.GetOrCreate_pPr(); var pPr = this.GetOrCreate_pPr();
var spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName)); var spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName));
if (spacing == null) if (spacing == null)
pPr.Add(new XElement(XName.Get("spacing", DocX.w.NamespaceName))); pPr.Add(new XElement(XName.Get("spacing", DocX.w.NamespaceName)));
spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName)); spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName));
} }
string spacingTypeAttribute = ""; string spacingTypeAttribute = "";
switch (spacingType) switch (spacingType)
{ {
case LineSpacingType.Line:
{
spacingTypeAttribute = "line";
break;
}
case LineSpacingType.Before:
{
spacingTypeAttribute = "before";
break;
}
case LineSpacingType.After:
{
spacingTypeAttribute = "after";
break;
}
case LineSpacingType.Line:
{
spacingTypeAttribute = "line";
break;
}
case LineSpacingType.Before:
{
spacingTypeAttribute = "before";
break;
}
case LineSpacingType.After:
{
spacingTypeAttribute = "after";
break;
}
} }
spacing.SetAttributeValue(XName.Get(spacingTypeAttribute, DocX.w.NamespaceName), spacingValue); spacing.SetAttributeValue(XName.Get(spacingTypeAttribute, DocX.w.NamespaceName), spacingValue);
} }
/// <summary> /// <summary>
/// Set the linespacing for this paragraph using the Auto value. /// Set the linespacing for this paragraph using the Auto value.
/// </summary> /// </summary>
public void SetLineSpacing(LineSpacingTypeAuto spacingType) public void SetLineSpacing(LineSpacingTypeAuto spacingType)
{ {
int spacingValue = 100; int spacingValue = 100;
var pPr = this.GetOrCreate_pPr(); var pPr = this.GetOrCreate_pPr();
var spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName)); var spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName));
if (spacingType.Equals(LineSpacingTypeAuto.None)) if (spacingType.Equals(LineSpacingTypeAuto.None))
{ {
if (spacing != null)
{
spacing.Remove();
}
if (spacing != null)
{
spacing.Remove();
}
} }
else {
if (spacing == null)
{
pPr.Add(new XElement(XName.Get("spacing", DocX.w.NamespaceName)));
spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName));
}
string spacingTypeAttribute = "";
string autoSpacingTypeAttribute = "";
switch (spacingType)
{
case LineSpacingTypeAuto.AutoBefore:
{
spacingTypeAttribute = "before";
autoSpacingTypeAttribute = "beforeAutospacing";
break;
}
case LineSpacingTypeAuto.AutoAfter:
{
spacingTypeAttribute = "after";
autoSpacingTypeAttribute = "afterAutospacing";
break;
}
case LineSpacingTypeAuto.Auto:
{
spacingTypeAttribute = "before";
autoSpacingTypeAttribute = "beforeAutospacing";
spacing.SetAttributeValue(XName.Get("after", DocX.w.NamespaceName), spacingValue);
spacing.SetAttributeValue(XName.Get("afterAutospacing", DocX.w.NamespaceName), 1);
break;
}
}
spacing.SetAttributeValue(XName.Get(autoSpacingTypeAttribute, DocX.w.NamespaceName), 1);
spacing.SetAttributeValue(XName.Get(spacingTypeAttribute, DocX.w.NamespaceName), spacingValue);
else
{
if (spacing == null)
{
pPr.Add(new XElement(XName.Get("spacing", DocX.w.NamespaceName)));
spacing = pPr.Element(XName.Get("spacing", DocX.w.NamespaceName));
}
string spacingTypeAttribute = "";
string autoSpacingTypeAttribute = "";
switch (spacingType)
{
case LineSpacingTypeAuto.AutoBefore:
{
spacingTypeAttribute = "before";
autoSpacingTypeAttribute = "beforeAutospacing";
break;
}
case LineSpacingTypeAuto.AutoAfter:
{
spacingTypeAttribute = "after";
autoSpacingTypeAttribute = "afterAutospacing";
break;
}
case LineSpacingTypeAuto.Auto:
{
spacingTypeAttribute = "before";
autoSpacingTypeAttribute = "beforeAutospacing";
spacing.SetAttributeValue(XName.Get("after", DocX.w.NamespaceName), spacingValue);
spacing.SetAttributeValue(XName.Get("afterAutospacing", DocX.w.NamespaceName), 1);
break;
}
}
spacing.SetAttributeValue(XName.Get(autoSpacingTypeAttribute, DocX.w.NamespaceName), 1);
spacing.SetAttributeValue(XName.Get(spacingTypeAttribute, DocX.w.NamespaceName), spacingValue);
} }
} }

+ 20
- 0
Examples/Program.cs Wyświetl plik

HyperlinksImagesTables(); HyperlinksImagesTables();
AddList(); AddList();
Equations(); Equations();
Bookmarks();
BarChart(); BarChart();
PieChart(); PieChart();
LineChart(); LineChart();
} }
} }
private static void Bookmarks()
{
Console.WriteLine("\nBookmarks()");
using (var document = DocX.Create(@"docs\Bookmarks.docx"))
{
var paragraph = document.InsertBookmark("firstBookmark");
var paragraph2 = document.InsertParagraph("This is a paragraph which contains a ");
paragraph2.AppendBookmark("secondBookmark");
paragraph2.Append("bookmark");
paragraph2.InsertAtBookmark("handy ", "secondBookmark");
document.Save();
Console.WriteLine("\tCreated: docs\\Bookmarks.docx\n");
}
}
/// <summary> /// <summary>
/// Create a document with a Paragraph whos first line is indented. /// Create a document with a Paragraph whos first line is indented.
/// </summary> /// </summary>

+ 4
- 4
UnitTests/DocXUnitTests.cs Wyświetl plik

using System; using System;
using System.Collections.Generic;
using System.Drawing;
using Novacode;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Drawing;
using System.Xml.Linq;
using System.Reflection; using System.Reflection;
using System.Collections.Generic;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using Novacode;
namespace UnitTests namespace UnitTests
{ {

+ 12
- 6
UnitTests/UnitTests.csproj Wyświetl plik

</CodeAnalysisDependentAssemblyPaths> </CodeAnalysisDependentAssemblyPaths>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="InsertAtBookmark.cs">
<DependentUpon>DocXUnitTests.cs</DependentUpon>
</Compile>
<Compile Include="AppendBookmark.cs">
<DependentUpon>DocXUnitTests.cs</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="DocXUnitTests.cs" /> <Compile Include="DocXUnitTests.cs" />
<Compile Include="RelativeDirectory.cs" /> <Compile Include="RelativeDirectory.cs" />
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
--> -->
</Project> </Project>

Ładowanie…
Anuluj
Zapisz