Upload to server

uploading
This commit is contained in:
2025-08-02 05:20:17 +07:00
commit a5eccbd452
984 changed files with 3031800 additions and 0 deletions

View File

@@ -0,0 +1,226 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.IO;
using System.Linq;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
public partial class WmlDocument : OpenXmlPowerToolsDocument
{
public string GetBackgroundColor()
{
return BackgroundAccessor.GetBackgroundColor(this);
}
public string GetBackgroundImageFileName()
{
return BackgroundAccessor.GetImageFileName(this);
}
public void SaveBackgroundImageToFile(string fileName)
{
BackgroundAccessor.SaveImageToFile(this, fileName);
}
public WmlDocument SetBackgroundColor(string colorValue)
{
return (WmlDocument)BackgroundAccessor.SetColor(this, colorValue);
}
public WmlDocument SetBackgroundImage(string imagePath)
{
return (WmlDocument)BackgroundAccessor.SetImage(this, imagePath);
}
}
/// <summary>
/// Provides access to background operations
/// </summary>
public class BackgroundAccessor
{
private const string defaultBackgroundColor = "FFFFFF";
private const string defaultBWMode = "white";
private const string defaultTargetScreenSize = "800,600";
private const string defaultVmlBackgroundImageId = "_x0000_s1025";
private const string defaultImageRecolor = "t";
private const string defaultImageType = "frame";
private static XNamespace ns;
private static XNamespace vmlns;
private static XNamespace officens;
private static XNamespace relationshipsns;
public static string GetBackgroundColor(WmlDocument doc)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
XElement backgroundElement = mainDocument.Descendants(W.background).FirstOrDefault();
return (backgroundElement == null) ? string.Empty : backgroundElement.Attribute(W.color).Value;
}
}
public static string GetImageFileName(WmlDocument doc)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
XElement fillElement = mainDocument.Descendants(W.background).Descendants(VML.fill).FirstOrDefault();
if (fillElement != null)
{
string imageRelationshipId = fillElement.Attribute(R.id).Value;
OpenXmlPart imagePart = document.MainDocumentPart.GetPartById(imageRelationshipId);
// Gets the image name (path stripped)
string imagePath = imagePart.Uri.OriginalString;
return imagePath.Substring(imagePath.LastIndexOf('/') + 1);
}
else
return string.Empty;
}
}
public static void SaveImageToFile(WmlDocument doc, string fileName)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
XElement fillElement = mainDocument.Descendants(W.background).Descendants(VML.fill).FirstOrDefault();
if (fillElement != null)
{
string imageRelationshipId = fillElement.Attribute(R.id).Value;
OpenXmlPart imagePart = document.MainDocumentPart.GetPartById(imageRelationshipId);
// Gets the image name (path stripped)
string imagePath = imagePart.Uri.OriginalString;
// Writes the image outside the package
OpenXmlPowerToolsDocument.SavePartAs(imagePart, fileName);
}
}
}
static BackgroundAccessor()
{
ns = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
vmlns = "urn:schemas-microsoft-com:vml";
officens = "urn:schemas-microsoft-com:office:office";
relationshipsns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
}
/// <summary>
/// Nodes list with background elements
/// </summary>
private static XElement BackgroundElement(WordprocessingDocument document)
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
XElement result = mainDocument.Descendants(ns + "background").FirstOrDefault();
return result;
}
/// <summary>
/// Nodes list with background elements
/// </summary>
private static XElement BackgroundFillElement(WordprocessingDocument document)
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
XElement result = mainDocument.Descendants(ns + "background").Descendants(vmlns + "fill").FirstOrDefault();
return result;
}
/// <summary>
/// Sets the document background color
/// </summary>
/// <param name="colorValue">String representation of the hexadecimal RGB color</param>
public static OpenXmlPowerToolsDocument SetColor(WmlDocument doc, string colorValue)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
// If the background element already exists, deletes it
XElement backgroundElement = BackgroundElement(document);
if (backgroundElement != null)
backgroundElement.Remove();
mainDocument.Root.AddFirst(
new XElement(ns + "background",
new XAttribute(ns + "color", colorValue)
)
);
// Enables background displaying by adding "displayBackgroundShape" tag
if (SettingAccessor.DisplayBackgroundShapeElements(document) == null)
SettingAccessor.AddBackgroundShapeElement(document);
document.MainDocumentPart.PutXDocument();
}
return streamDoc.GetModifiedDocument();
}
}
/// <summary>
/// Sets the document background image
/// </summary>
/// <param name="imagePath">Path of the background image</param>
public static OpenXmlPowerToolsDocument SetImage(WmlDocument doc, string imagePath)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
// Adds the image to the package
ImagePart imagePart = document.MainDocumentPart.AddImagePart(ImagePartType.Bmp);
Stream imageStream = new StreamReader(imagePath).BaseStream;
byte[] imageBytes = new byte[imageStream.Length];
imageStream.Read(imageBytes, 0, imageBytes.Length);
imagePart.GetStream().Write(imageBytes, 0, imageBytes.Length);
// Creates a "background" element relating the image and the document
// If the background element already exists, deletes it
XElement backgroundElement = BackgroundElement(document);
if (backgroundElement != null)
backgroundElement.Remove();
// Background element construction
mainDocument.Root.Add(
new XElement(ns + "background",
new XAttribute(ns + "color", defaultBackgroundColor),
new XElement(vmlns + "background",
new XAttribute(vmlns + "id", defaultVmlBackgroundImageId),
new XAttribute(officens + "bwmode", defaultBWMode),
new XAttribute(officens + "targetscreensize", defaultTargetScreenSize),
new XElement(vmlns + "fill",
new XAttribute(relationshipsns + "id", document.MainDocumentPart.GetIdOfPart(imagePart)),
new XAttribute("recolor", defaultImageRecolor),
new XAttribute("type", defaultImageType)
)
)
)
);
// Enables background displaying by adding "displayBackgroundShape" tag
if (SettingAccessor.DisplayBackgroundShapeElements(document) == null)
SettingAccessor.AddBackgroundShapeElement(document);
document.MainDocumentPart.PutXDocument();
}
return streamDoc.GetModifiedDocument();
}
}
}
}

View File

@@ -0,0 +1,545 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
/// <summary>
/// Chart types available
/// </summary>
public enum ChartType
{
/// <summary>
/// Bar
/// </summary>
Bar,
/// <summary>
/// Column
/// </summary>
Column,
/// <summary>
/// Line
/// </summary>
Line,
/// <summary>
/// Area
/// </summary>
Area,
/// <summary>
/// Pie
/// </summary>
Pie
}
/// <summary>
/// Provides access to chartsheet operations
/// </summary>
public class ChartsheetAccessor
{
private const int defaultAnchorPosX = 0;
private const int defaultAnchorPosY = 0;
private const int defaultAnchorExtX = 8673523;
private const int defaultAnchorExtY = 6306705;
private const string defaultLegendPosition = "r";
private static XNamespace ns;
private static XNamespace relationshipsns;
private static XNamespace sdrns;
private static XNamespace drawingns;
private static XNamespace chartns;
static ChartsheetAccessor()
{
ns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
relationshipsns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
sdrns = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing";
drawingns = "http://schemas.openxmlformats.org/drawingml/2006/main";
chartns = "http://schemas.openxmlformats.org/drawingml/2006/chart";
}
/// <summary>
/// Creates a chartsheet part from given data
/// </summary>
/// <param name="chartType">Type of chart to generate</param>
/// <param name="values">Values to represent in the chart</param>
/// <param name="headerReference">Columns to be used as series</param>
/// <param name="categoryReference">Column to be used as category</param>
/// <returns>Chartsheet part with contents related</returns>
public static ChartsheetPart Create(SpreadsheetDocument parentDocument, ChartType chartType, List<string> values, List<string> headerReference, string categoryReference)
{
//Creates base content and associates it to a new chartsheet part
WorkbookPart workbook = parentDocument.WorkbookPart;
ChartsheetPart chartsheetPart = workbook.AddNewPart<ChartsheetPart>();
XDocument chartsheetDocument = CreateEmptyChartsheet();
chartsheetPart.PutXDocument(chartsheetDocument);
//Creates a base drawings part and associates it to the chartsheet part
DrawingsPart drawingsPart = chartsheetPart.AddNewPart<DrawingsPart>();
XDocument drawingDocument = CreateEmptyDrawing();
drawingsPart.PutXDocument(drawingDocument);
//Adds content to chartsheet document to reference drawing document
chartsheetDocument
.Element(ns + "chartsheet")
.Add(
new XElement(ns + "drawing",
new XAttribute(relationshipsns + "id", chartsheetPart.GetIdOfPart(drawingsPart))
)
);
//creates the chart part and associates it to the drawings part
ChartPart chartPart = drawingsPart.AddNewPart<ChartPart>();
XDocument chartDocument = CreateChart(chartType, values, headerReference, categoryReference);
chartPart.PutXDocument(chartDocument);
//Adds content to drawing document to reference chart document
drawingDocument
.Descendants(drawingns + "graphicData")
.First()
.Add(
new XAttribute("uri", chartns),
new XElement(chartns + "chart",
new XAttribute(XNamespace.Xmlns + "c", chartns),
new XAttribute(XNamespace.Xmlns + "r", relationshipsns),
new XAttribute(relationshipsns + "id", drawingsPart.GetIdOfPart(chartPart))
)
);
//Associates the chartsheet part to the workbook part
XDocument document = parentDocument.WorkbookPart.GetXDocument();
int sheetId = document.Root.Element(ns + "sheets").Elements(ns + "sheet").Count() + 1;
int chartsheetCount =
document.Root
.Element(ns + "sheets")
.Elements(ns + "sheet")
.Where(
t =>
t.Attribute("name").Value.StartsWith("chart")
)
.Count() + 1;
//Adds content to workbook document to reference chartsheet document
document.Root
.Element(ns + "sheets")
.Add(
new XElement(ns + "sheet",
new XAttribute("name", string.Format("chart{0}", chartsheetCount)),
new XAttribute("sheetId", sheetId),
new XAttribute(relationshipsns + "id", workbook.GetIdOfPart(chartsheetPart))
)
);
chartsheetPart.PutXDocument();
drawingsPart.PutXDocument();
parentDocument.WorkbookPart.PutXDocument();
return chartsheetPart;
}
/// <summary>
/// Creates element structure needed to describe an empty worksheet
/// </summary>
/// <returns>Document with contents for an empty worksheet</returns>
private static XDocument CreateEmptyChartsheet()
{
XDocument document =
new XDocument(
new XElement(ns + "chartsheet",
new XAttribute("xmlns", ns),
new XAttribute(XNamespace.Xmlns + "r", relationshipsns),
new XElement(ns + "sheetViews",
new XElement(ns + "sheetView",
new XAttribute("workbookViewId", 0)
)
)
)
);
return document;
}
/// <summary>
/// Creates tags to describe an empty row
/// </summary>
/// <param name="row"></param>
/// <returns></returns>
private static XElement CreateEmptyRow(int row)
{
XElement rowElement =
new XElement(ns + "row",
new XAttribute("r", row)
);
return rowElement;
}
/// <summary>
/// Creates element structure needed to describe an empty drawing
/// </summary>
private static XDocument CreateEmptyDrawing()
{
return new XDocument(
new XElement(sdrns + "wsDr",
new XAttribute(XNamespace.Xmlns + "xdr", sdrns),
new XAttribute(XNamespace.Xmlns + "a", drawingns),
new XElement(sdrns + "absoluteAnchor",
new XElement(sdrns + "pos",
new XAttribute("x", defaultAnchorPosX),
new XAttribute("y", defaultAnchorPosY)
),
new XElement(sdrns + "ext",
new XAttribute("cx", defaultAnchorExtX),
new XAttribute("cy", defaultAnchorExtY)
),
new XElement(sdrns + "graphicFrame",
new XAttribute("macro", string.Empty),
new XElement(sdrns + "nvGraphicFramePr",
new XElement(sdrns + "cNvPr",
new XAttribute("id", 2),
new XAttribute("name", "Chart 1")
),
new XElement(sdrns + "cNvGraphicFramePr",
new XElement(drawingns + "graphicFrameLocks",
new XAttribute("noGrp", "1")
)
)
),
new XElement(sdrns + "xfrm",
new XElement(drawingns + "off",
new XAttribute("x", 0),
new XAttribute("y", 0)
),
new XElement(drawingns + "ext",
new XAttribute("cx", 0),
new XAttribute("cy", 0)
)
),
new XElement(drawingns + "graphic",
new XElement(drawingns + "graphicData")
)
),
new XElement(sdrns + "clientData")
)
)
);
}
/// <summary>
/// Creates element structure needed to describe an empty chart
/// </summary>
private static XDocument CreateEmptyChart()
{
return new XDocument(
new XElement(chartns + "chartSpace",
new XAttribute(XNamespace.Xmlns + "c", chartns),
new XAttribute(XNamespace.Xmlns + "a", drawingns),
new XAttribute(XNamespace.Xmlns + "r", relationshipsns),
new XElement(chartns + "chart",
new XElement(chartns + "title",
new XElement(chartns + "layout")
),
new XElement(chartns + "plotArea",
new XElement(chartns + "layout")
),
new XElement(chartns + "legend",
new XElement(chartns + "legendPos",
new XAttribute("val", defaultLegendPosition)
),
new XElement(chartns + "layout")
)
)
)
);
}
/// <summary>
/// Creates element structure needed to describe a chart with data related
/// </summary>
private static XDocument CreateChart(ChartType chartType, IEnumerable<string> seriesReferences, IEnumerable<string> seriesTitles, string category)
{
XDocument chartDocument = CreateEmptyChart();
XElement chartElement =
chartDocument
.Element(chartns + "chartSpace")
.Element(chartns + "chart")
.Element(chartns + "plotArea");
string categoryAxisId = "28819";
string valueAxisId = "28818";
//Chooses the right chart type
switch (chartType)
{
case ChartType.Bar:
chartElement.Add(
CreateBarChart(seriesReferences, seriesTitles, category, categoryAxisId, valueAxisId),
CreateCategoryAxis(categoryAxisId, valueAxisId),
CreateValueAxis(valueAxisId, categoryAxisId)
);
break;
case ChartType.Column:
chartElement.Add(
CreateColumnChart(seriesReferences, seriesTitles, category, categoryAxisId, valueAxisId),
CreateCategoryAxis(categoryAxisId, valueAxisId),
CreateValueAxis(valueAxisId, categoryAxisId)
);
break;
case ChartType.Line:
chartElement.Add(
CreateLineChart(seriesReferences, seriesTitles, category, categoryAxisId, valueAxisId),
CreateCategoryAxis(categoryAxisId, valueAxisId),
CreateValueAxis(valueAxisId, categoryAxisId)
);
break;
case ChartType.Area:
chartElement.Add(
CreateAreaChart(seriesReferences, seriesTitles, category, categoryAxisId, valueAxisId),
CreateCategoryAxis(categoryAxisId, valueAxisId),
CreateValueAxis(valueAxisId, categoryAxisId)
);
break;
case ChartType.Pie:
chartElement.Add(
CreatePieChart(seriesReferences, seriesTitles, category, categoryAxisId, valueAxisId)
);
break;
}
return chartDocument;
}
/// <summary>
/// Creates element structure needed to describe a column chart with data related
/// </summary>
private static XElement CreateColumnChart(IEnumerable<string> seriesReferences, IEnumerable<string> seriesTitles, string category, string categoryAxisId, string valueAxisId)
{
return new XElement(chartns + "barChart",
new XElement(chartns + "barDir",
new XAttribute("val", "col")
),
new XElement(chartns + "grouping",
new XAttribute("val", "clustered")
),
CreateSeries(seriesReferences, seriesTitles, category),
seriesReferences.Count() < 1 ?
new XElement(chartns + "gapWidth",
new XAttribute("val", 100)
)
: null,
new XElement(chartns + "axId",
new XAttribute("val", categoryAxisId)
),
new XElement(chartns + "axId",
new XAttribute("val", valueAxisId)
)
);
}
/// <summary>
/// Creates element structure needed to describe a bar chart with data related
/// </summary>
private static XElement CreateBarChart(IEnumerable<string> seriesReferences, IEnumerable<string> seriesTitles, string category, string categoryAxisId, string valueAxisId)
{
return new XElement(chartns + "barChart",
new XElement(chartns + "barDir",
new XAttribute("val", "bar")
),
new XElement(chartns + "grouping",
new XAttribute("val", "clustered")
),
CreateSeries(seriesReferences, seriesTitles, category),
seriesReferences.Count() < 1 ?
new XElement(chartns + "gapWidth",
new XAttribute("val", 100)
)
: null,
new XElement(chartns + "axId",
new XAttribute("val", categoryAxisId)
),
new XElement(chartns + "axId",
new XAttribute("val", valueAxisId)
)
);
}
/// <summary>
/// Creates element structure needed to describe a line chart with data related
/// </summary>
private static XElement CreateLineChart(IEnumerable<string> seriesReferences, IEnumerable<string> seriesTitles, string category, string categoryAxisId, string valueAxisId)
{
return new XElement(chartns + "lineChart",
new XElement(chartns + "grouping",
new XAttribute("val", "standard")
),
CreateSeries(seriesReferences, seriesTitles, category),
new XElement(chartns + "marker",
new XAttribute("val", 1)
),
new XElement(chartns + "axId",
new XAttribute("val", categoryAxisId)
),
new XElement(chartns + "axId",
new XAttribute("val", valueAxisId)
)
);
}
/// <summary>
/// Creates element structure needed to describe an area chart with data related
/// </summary>
private static XElement CreateAreaChart(IEnumerable<string> seriesReferences, IEnumerable<string> seriesTitles, string category, string categoryAxisId, string valueAxisId)
{
return new XElement(chartns + "areaChart",
new XElement(chartns + "grouping",
new XAttribute("val", "stacked")
),
CreateSeries(seriesReferences, seriesTitles, category),
new XElement(chartns + "axId",
new XAttribute("val", categoryAxisId)
),
new XElement(chartns + "axId",
new XAttribute("val", valueAxisId)
)
);
}
/// <summary>
/// Creates element structure needed to describe a pie chart with data related
/// </summary>
private static XElement CreatePieChart(IEnumerable<string> seriesReferences, IEnumerable<string> seriesTitles, string category, string categoryAxisId, string valueAxisId)
{
return new XElement(chartns + "pieChart",
new XElement(chartns + "varyColors",
new XAttribute("val", 1)
),
CreateSeries(seriesReferences, seriesTitles, category),
new XElement(chartns + "firstSliceAng",
new XAttribute("val", 0)
)
);
}
/// <summary>
/// Creates element structure needed to describe a data series
/// </summary>
private static IEnumerable<XElement> CreateSeries(IEnumerable<string> seriesReference, IEnumerable<string> seriesTitles, string category)
{
List<XElement> seriesList = new List<XElement>();
int numSeries = 0;
foreach (var series in seriesReference)
{
seriesList.Add(
new XElement(chartns + "ser",
new XElement(chartns + "idx",
new XAttribute("val", numSeries)
),
new XElement(chartns + "order",
new XAttribute("val", numSeries)
),
new XElement(chartns + "tx",
new XElement(chartns + "strRef",
new XElement(chartns + "f", seriesTitles.ElementAt(numSeries))
)
),
new XElement(chartns + "cat",
new XElement(chartns + "strRef",
new XElement(chartns + "f", category)
)
),
new XElement(chartns + "val",
new XElement(chartns + "numRef",
new XElement(chartns + "f", series)
)
)
)
);
numSeries++;
}
return seriesList;
}
/// <summary>
/// Creates element structure needed to describe a category axis
/// </summary>
private static XElement CreateCategoryAxis(string categoryAxisId, string valueAxisId)
{
return new XElement(chartns + "catAx",
new XElement(chartns + "axId",
new XAttribute("val", categoryAxisId)
),
new XElement(chartns + "scaling",
new XElement(chartns + "orientation",
new XAttribute("val", "minMax")
)
),
new XElement(chartns + "axPos",
new XAttribute("val", "b")
),
new XElement(chartns + "tickLblPos",
new XAttribute("val", "nextTo")
),
new XElement(chartns + "crossAx",
new XAttribute("val", valueAxisId)
),
new XElement(chartns + "crosses",
new XAttribute("val", "autoZero")
),
new XElement(chartns + "auto",
new XAttribute("val", 1)
),
new XElement(chartns + "lblAlgn",
new XAttribute("val", "ctr")
),
new XElement(chartns + "lblOffset",
new XAttribute("val", 100)
)
);
}
/// <summary>
/// Creates element structure needed to describe a value axis
/// </summary>
private static XElement CreateValueAxis(string valueAxisId, string categoryAxisId)
{
return new XElement(chartns + "valAx",
new XElement(chartns + "axId",
new XAttribute("val", valueAxisId)
),
new XElement(chartns + "scaling",
new XElement(chartns + "orientation",
new XAttribute("val", "minMax")
)
),
new XElement(chartns + "axPos",
new XAttribute("val", "l")
),
new XElement(chartns + "majorGridlines"),
new XElement(chartns + "numFmt",
new XAttribute("formatCode", "General"),
new XAttribute("sourceLinked", "1")
),
new XElement(chartns + "tickLblPos",
new XAttribute("val", "nextTo")
),
new XElement(chartns + "crossAx",
new XAttribute("val", categoryAxisId)
),
new XElement(chartns + "crosses",
new XAttribute("val", "autoZero")
),
new XElement(chartns + "crossBetween",
new XAttribute("val", "between")
)
);
}
}
}

View File

@@ -0,0 +1,124 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
public partial class WmlDocument : OpenXmlPowerToolsDocument
{
public object GetAllComments(CommentFormat format)
{
return CommentAccessor.GetAllComments(this, format);
}
}
public enum CommentFormat
{
PlainText,
Xml,
Docx
}
/// <summary>
/// Provides access to comment operations
/// </summary>
public class CommentAccessor
{
public static object GetAllComments(WmlDocument doc, CommentFormat format)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
IEnumerable<XElement> comments = null;
WordprocessingCommentsPart commentsPart = document.MainDocumentPart.WordprocessingCommentsPart;
if (commentsPart != null)
{
XDocument commentsPartDocument = commentsPart.GetXDocument();
comments = commentsPartDocument.Element(W.comments).Elements(W.comment);
}
if (comments != null)
{
XDocument commentsDocument =
new XDocument(
new XElement(W.comments,
new XAttribute(XNamespace.Xmlns + "w", W.w),
comments
)
);
switch (format)
{
case CommentFormat.PlainText:
return commentsDocument.ToString();
case CommentFormat.Xml:
return commentsDocument;
case CommentFormat.Docx:
return CreateCommentsDocument(comments);
}
}
return null;
}
}
private static OpenXmlPowerToolsDocument CreateCommentsDocument(IEnumerable<XElement> contents)
{
using (OpenXmlMemoryStreamDocument streamDoc = OpenXmlMemoryStreamDocument.CreateWordprocessingDocument())
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
PowerToolsExtensions.SetContent(document, contents);
}
return streamDoc.GetModifiedDocument();
}
}
/// <summary>
/// Returns all reference tags from inside the main part of a wordprocessing document
/// </summary>
private static IEnumerable<XElement> CommentReferences(WordprocessingDocument document)
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
IEnumerable<XElement> results =
mainDocument.Descendants().Where(
tag =>
tag.Name == W.commentRangeStart ||
tag.Name == W.commentRangeEnd ||
(tag.Name == W.r && tag.Descendants(W.commentReference).Count() > 0)
);
return results;
}
/// <summary>
/// Removes all of the comments existing in the document
/// </summary>
public static OpenXmlPowerToolsDocument RemoveAll(WmlDocument doc)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
//Removes comment-related tags inside the main document part
IEnumerable<XElement> commentReferences = CommentReferences(document).ToList();
commentReferences.Remove();
document.MainDocumentPart.PutXDocument();
WordprocessingCommentsPart commentsPart = document.MainDocumentPart.WordprocessingCommentsPart;
if (commentsPart != null)
commentsPart.RemovePart();
}
return streamDoc.GetModifiedDocument();
}
}
}
}

View File

@@ -0,0 +1,672 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
using System.IO;
namespace OpenXmlPowerTools
{
public partial class WmlDocument : OpenXmlPowerToolsDocument
{
public WmlDocument MergeComments(WmlDocument other)
{
return CommentMerger.MergeComments(this, other);
}
}
public class CommentMergerInternalException : Exception
{
public CommentMergerInternalException(string message) : base(message) { }
}
public class CommentMergerDifferingContentsException : Exception
{
public CommentMergerDifferingContentsException(string message) : base(message) { }
}
public class CommentMergerUnlockedDocumentException : Exception
{
public CommentMergerUnlockedDocumentException(string message) : base(message) { }
}
public class CommentMerger
{
public static WmlDocument MergeComments(WmlDocument document1, WmlDocument document2)
{
return MergeComments(document1, document2, true);
}
public static WmlDocument MergeComments(WmlDocument document1, WmlDocument document2,
bool ensureLocked)
{
WmlDocument cDoc1 = new WmlDocument(document1);
WmlDocument cDoc2 = new WmlDocument(document2);
using (OpenXmlMemoryStreamDocument streamDoc1 = new OpenXmlMemoryStreamDocument(cDoc1))
using (WordprocessingDocument doc1 = streamDoc1.GetWordprocessingDocument())
using (OpenXmlMemoryStreamDocument streamDoc2 = new OpenXmlMemoryStreamDocument(cDoc2))
using (WordprocessingDocument doc2 = streamDoc2.GetWordprocessingDocument())
{
SimplifyMarkupSettings mss = new SimplifyMarkupSettings()
{
RemoveProof = true,
RemoveRsidInfo = true,
RemoveGoBackBookmark = true,
};
MarkupSimplifier.SimplifyMarkup(doc1, mss);
MarkupSimplifier.SimplifyMarkup(doc2, mss);
// If documents don't contain the same content, then don't attempt to merge comments.
bool same = DocumentComparer.CompareDocuments(doc1, doc2);
if (!same)
throw new CommentMergerDifferingContentsException(
"Documents do not contain the same content");
if (doc1.MainDocumentPart.WordprocessingCommentsPart == null &&
doc2.MainDocumentPart.WordprocessingCommentsPart == null)
return new WmlDocument(document1);
if (doc1.MainDocumentPart.WordprocessingCommentsPart != null &&
doc2.MainDocumentPart.WordprocessingCommentsPart == null)
return new WmlDocument(document1);
if (doc1.MainDocumentPart.WordprocessingCommentsPart == null &&
doc2.MainDocumentPart.WordprocessingCommentsPart != null)
return new WmlDocument(document2);
// If either of the documents have no comments, then return the other one.
if (! doc1.MainDocumentPart.WordprocessingCommentsPart.GetXDocument().Root
.Elements(W.comment).Any())
return new WmlDocument(document2);
if (! doc2.MainDocumentPart.WordprocessingCommentsPart.GetXDocument().Root
.Elements(W.comment).Any())
return new WmlDocument(document1);
if (ensureLocked)
{
// If either document is not locked (allowing only commenting), don't attempt to
// merge comments.
if (doc1.ExtendedFilePropertiesPart.GetXDocument().Root
.Element(EP.DocSecurity).Value != "8")
throw new CommentMergerUnlockedDocumentException(
"Document1 is not locked");
if (doc2.ExtendedFilePropertiesPart.GetXDocument().Root
.Element(EP.DocSecurity).Value != "8")
throw new CommentMergerUnlockedDocumentException(
"Document2 is not locked");
}
RenumberCommentsInDoc2(doc1, doc2);
WmlDocument destDoc = new WmlDocument(document1);
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(destDoc))
{
using (WordprocessingDocument destWDoc = streamDoc.GetWordprocessingDocument())
{
// Merge the comments part.
XDocument commentsPartXDoc = new XDocument(
new XElement(W.comments,
new XAttribute(XNamespace.Xmlns + "w", W.w),
doc1.MainDocumentPart.WordprocessingCommentsPart.GetXDocument().Root.Elements(),
doc2.MainDocumentPart.WordprocessingCommentsPart.GetXDocument().Root.Elements()));
destWDoc.MainDocumentPart.WordprocessingCommentsPart.PutXDocument(commentsPartXDoc);
MergeCommentsInPart(doc1.MainDocumentPart, doc2.MainDocumentPart,
destWDoc.MainDocumentPart, commentsPartXDoc);
}
return streamDoc.GetModifiedWmlDocument();
}
}
}
private static bool IsCommentElement(XElement e)
{
return e.Name == W.commentRangeStart || e.Name == W.commentRangeEnd ||
e.Name == W.commentReference;
}
private static IEnumerable<object> SplitElements(IEnumerable<XElement> elements)
{
IEnumerable<object> splitElements = elements
.Select(e =>
{
if ((e.Name == W.r && e.Elements(W.t).Any()) ||
(e.Name == M.r && e.Elements(M.t).Any()))
{
var grouped = e.Elements().Where(ce => ce.Name != W.rPr && ce.Name != M.rPr)
.GroupAdjacent(ce =>
(ce.Name == W.t || ce.Name == M.t));
return grouped.Select(g =>
{
if (g.Key == true)
{
string s = g.Select(t => (string)t).StringConcatenate();
return s.Select(c => new XElement(e.Name,
e.Attributes(),
e.Elements(W.rPr),
e.Elements(M.rPr),
new XElement(g.First().Name, c)));
}
return g.Select(ce => new XElement(e.Name,
e.Attributes(),
e.Elements(W.rPr),
e.Elements(M.rPr),
ce));
});
}
return (object)e;
});
return splitElements;
}
private class RunOrderingInfo
{
public int Integer;
public bool IsRun;
public RunOrderingInfo(int integer, bool isRun)
{
Integer = integer;
IsRun = isRun;
}
public RunOrderingInfo(int integer)
{
Integer = integer;
IsRun = false;
}
}
private static XName[] RunContentElements = new[]
{
M.t,
W.br,
W.cr,
W.dayLong,
W.dayShort,
W.drawing,
W.endnoteReference,
W.fldChar,
W.footnoteReference,
W.instrText,
W.lastRenderedPageBreak,
W.monthLong,
W.monthShort,
W.noBreakHyphen,
W._object,
W.ptab,
W.ruby,
W.softHyphen,
W.sym,
W.t,
W.tab,
W.yearLong,
W.yearShort,
};
private static void AddAnnotationsToChildren(XElement parent)
{
int index = 1000;
foreach (var ce in parent
.Elements().Where(e => e.Name == W.r || e.Name == M.r)
.Where(r =>
{
foreach (var item in RunContentElements)
if (r.Element(item) != null)
return true;
return false;
}))
{
ce.AddAnnotation(new RunOrderingInfo(index, true));
index += 1000;
}
foreach (var ce in parent.Elements().Where(e => e.Annotation<RunOrderingInfo>() == null))
{
var elementWithAnnoAfter = ce
.ElementsAfterSelf()
.FirstOrDefault(e => e.Annotation<RunOrderingInfo>() != null);
if (elementWithAnnoAfter != null)
{
int nextIndex = elementWithAnnoAfter.Annotation<RunOrderingInfo>().Integer;
var elementsAfter = ce.ElementsAfterSelf()
.TakeWhile(ea => ea.Annotation<RunOrderingInfo>() == null);
ce.AddAnnotation(new RunOrderingInfo(nextIndex - elementsAfter.Count() - 1));
continue;
}
// The element before must have an annotation.
var elementBefore = ce.ElementsBeforeSelfReverseDocumentOrder().FirstOrDefault();
if (elementBefore != null)
{
RunOrderingInfo elementBeforeAnnotation = elementBefore.Annotation<RunOrderingInfo>();
ce.AddAnnotation(new RunOrderingInfo(elementBeforeAnnotation.Integer + 1));
}
}
}
private static XAttribute GetXmlSpaceAttribute(
string textElementValue)
{
if (textElementValue.Length > 0 &&
(textElementValue[0] == ' ' ||
textElementValue[textElementValue.Length - 1] == ' '))
return new XAttribute(XNamespace.Xml + "space",
"preserve");
return null;
}
private static XElement MergeElementWithChildrenCommentElements(XElement e1, XElement e2,
XDocument commentsPartXDoc)
{
if (e1.Name.Namespace != W.w)
Console.WriteLine("processing mathml");
if (e1.Name != e2.Name)
throw new CommentMergerInternalException(
"attempting to merge elements that do not match up.");
var split1 = SplitElements(e1.Elements());
var split2 = SplitElements(e2.Elements());
XElement temp1 = new XElement(e1.Name,
e1.Attributes(),
split1);
XElement temp2 = new XElement(e2.Name,
e2.Attributes(),
split2);
// todo may want to remove following test.
if (temp1.Elements().Where(e => e.Name == W.r || e.Name == M.r).Where(r =>
{
foreach (var item in RunContentElements)
if (r.Element(item) != null)
return true;
return false;
}).Count() !=
temp2.Elements().Where(e => e.Name == W.r || e.Name == M.r).Where(r =>
{
foreach (var item in RunContentElements)
if (r.Element(item) != null)
return true;
return false;
}).Count())
throw new CommentMergerInternalException("runs do not line up");
AddAnnotationsToChildren(temp1);
AddAnnotationsToChildren(temp2);
if (temp1.Elements().Any(e => e.Annotation<RunOrderingInfo>() == null) ||
temp2.Elements().Any(e => e.Annotation<RunOrderingInfo>() == null))
throw new CommentMergerInternalException("some child does not have annotation");
var m = temp1
.Elements()
.Concat(temp2.Elements())
.OrderBy(e => e.Annotation<RunOrderingInfo>().Integer)
.GroupAdjacent(e => e.Annotation<RunOrderingInfo>().Integer);
XElement mergedElementWithSplitRuns = new XElement(e1.Name,
e1.Attributes(),
m.Select(g =>
{
if (g.First().Annotation<RunOrderingInfo>().IsRun)
return (object)g.First();
else
return g;
}));
// The following query serves to remove duplicate comments, i.e. the same exact
// comment from the same person is in each of the documents being merged.
var groupedCommentReferences = mergedElementWithSplitRuns.Elements()
.GroupAdjacent(e =>
{
if (e.Name == W.r || e.Name == M.r)
{
bool onlyOneChild = e.Elements().Where(z => z.Name != W.rPr).Count() == 1;
if (onlyOneChild)
{
XElement child = e.Elements().Where(z => z.Name != W.rPr).First();
if (child.Name == W.commentRangeStart ||
child.Name == W.commentRangeEnd ||
child.Name == W.commentReference)
{
XElement comment = commentsPartXDoc.Root
.Elements(W.comment)
.Where(c => (string)c.Attribute(W.id) == (string)child.Attribute(W.id))
.FirstOrDefault();
string s = child.Name.LocalName + "|" +
comment.Attribute(W.author).Value + "|" +
comment.Attribute(W.date).Value + "|" +
comment.Attribute(W.initials).Value + "|" +
comment.Descendants()
.Where(d => d.Name == W.t || d.Name == M.t)
.Select(t => (string)t).StringConcatenate();
return s;
}
}
}
if (e.Name != W.commentRangeStart &&
e.Name != W.commentRangeEnd &&
e.Name != W.commentReference)
return "NotAComment";
XElement comment2 = commentsPartXDoc.Root
.Elements(W.comment)
.Where(c => (string)c.Attribute(W.id) == (string)e.Attribute(W.id))
.FirstOrDefault();
string s2 = e.Name.LocalName + "|" +
comment2.Attribute(W.author).Value + "|" +
comment2.Attribute(W.date).Value + "|" +
comment2.Attribute(W.initials).Value + "|" +
comment2.Descendants()
.Where(d => d.Name == W.t || d.Name == M.t)
.Select(t => (string)t).StringConcatenate();
return s2;
});
XElement duplicateCommentsEliminated = new XElement(e1.Name,
e1.Attributes(),
groupedCommentReferences
.Select(g =>
{
if (g.Key == "NotAComment")
return (object)g;
return g.First();
}));
var runGroups = duplicateCommentsEliminated.Elements()
.GroupAdjacent(r =>
{
if (r.Name != W.r && r.Name != M.r)
return "NotRuns";
if (! r.Elements().Where(e => e.Name == W.rPr || e.Name == M.rPr).Any())
return "NoRunProperties";
XElement frag = new XElement("frag",
new XAttribute(XNamespace.Xmlns + "w", W.w),
r.Elements().Where(e => e.Name == W.rPr || e.Name == M.rPr));
return frag.ToString(
SaveOptions.DisableFormatting);
});
XElement newParagraph = new XElement(e1.Name,
e1.Attributes(),
runGroups.Select(g =>
{
if (g.Key == "NotRuns")
return (object)g;
if (g.Key == "NoRunProperties")
{
XElement newRun = new XElement(g.First().Name,
g.First().Attributes(),
g.Elements()
.GroupAdjacent(c => c.Name)
.Select(gc =>
{
if (gc.Key != W.t && gc.Key != M.t)
return (object)gc;
string textElementValue =
gc.Select(t => (string)t)
.StringConcatenate();
return new XElement(gc.First().Name.Namespace + "t",
GetXmlSpaceAttribute(
textElementValue),
textElementValue);
}));
return newRun;
}
XElement runPropertyFragment = XElement.Parse(
g.Key);
runPropertyFragment.Elements().Attributes()
.Where(a => a.IsNamespaceDeclaration)
.Remove();
XElement newRunWithProperties = new XElement(g.First().Name.Namespace + "r",
runPropertyFragment.Elements(),
g.Elements()
.Where(e => e.Name != W.rPr && e.Name != M.rPr)
.GroupAdjacent(c => c.Name)
.Select(gc =>
{
if (gc.Key != W.t && gc.Key != M.t)
return (object)gc;
string textElementValue = gc
.Select(t => (string)t)
.StringConcatenate();
return new XElement(gc.Key,
GetXmlSpaceAttribute(textElementValue),
textElementValue);
}));
return newRunWithProperties;
}
));
return newParagraph;
}
private static object MergeElementTransform(XElement e1, XElement e2, XDocument commentsPartXDoc)
{
// todo need better message
if (e1.Name != e2.Name)
throw new CommentMergerDifferingContentsException("Internal error");
if (e1.Elements()
.Where(e => IsCommentElement(e)).Any() || e2.Elements().Where(e => IsCommentElement(e))
.Any())
return MergeElementWithChildrenCommentElements(e1, e2, commentsPartXDoc);
var zippedChildren = e1.Elements().Zip(e2.Elements(), (p1, p2) => new
{
Element1 = p1,
Element2 = p2,
});
return new XElement(e1.Name,
e1.Attributes(),
zippedChildren.Select(z =>
{
if (z.Element1.Name == W.t && z.Element2.Name == W.t &&
z.Element1.Value == z.Element2.Value)
return new XElement(W.t,
GetXmlSpaceAttribute(z.Element1.Value),
z.Element1.Value);
if (z.Element1.Name == M.t && z.Element2.Name == M.t &&
z.Element1.Value == z.Element2.Value)
return new XElement(M.t,
GetXmlSpaceAttribute(z.Element1.Value),
z.Element1.Value);
return MergeElementTransform(z.Element1, z.Element2, commentsPartXDoc);
}));
}
private static void MergeCommentsInPart(OpenXmlPart part1, OpenXmlPart part2,
OpenXmlPart destinationPart, XDocument commentsPartXDoc)
{
XDocument xdoc1 = part1.GetXDocument();
XDocument xdoc2 = part2.GetXDocument();
XElement newRootElement = (XElement)MergeElementTransform(xdoc1.Root, xdoc2.Root,
commentsPartXDoc);
destinationPart.PutXDocument(new XDocument(newRootElement));
}
// todo are there any other elements that need ids fixed? see children of paragraph, run
private static void FixIdsInPart(OpenXmlPart part, int nextCommentId, int nextBookmarkId)
{
if (part == null)
return;
foreach (var element in part.GetXDocument().Root.Descendants()
.Where(e => e.Name == W.commentRangeStart ||
e.Name == W.commentRangeEnd ||
e.Name == W.commentReference))
element.Attribute(W.id).Value = ((int)element.Attribute(W.id) + nextCommentId).ToString();
foreach (var element in part.GetXDocument().Root.Descendants()
.Where(e => e.Name == W.bookmarkStart || e.Name == W.bookmarkEnd))
element.Attribute(W.id).Value = ((int)element.Attribute(W.id) + nextBookmarkId).ToString();
}
private static void RenumberCommentsInDoc2(WordprocessingDocument doc1, WordprocessingDocument doc2)
{
// Get the XDocuments for the two comments parts.
XDocument doc1WordprocessingCommentsXDocument = doc1
.MainDocumentPart
.WordprocessingCommentsPart
.GetXDocument();
int commentIdIncrease = doc1WordprocessingCommentsXDocument
.Root
.Elements(W.comment)
.Attributes(W.id)
.Select(a => (int)a)
.Max() + 1;
int nextBookmarkId = new[] { 0 }
.Concat(doc1.MainDocumentPart
.GetXDocument()
.Root
.Descendants(W.bookmarkStart)
.Attributes(W.id)
.Select(a => (int)a))
.Max();
foreach (var part in doc1.MainDocumentPart.HeaderParts)
nextBookmarkId = new[] { nextBookmarkId }
.Concat(part
.GetXDocument()
.Root
.Descendants(W.bookmarkStart)
.Attributes(W.id)
.Select(a => (int)a))
.Max();
foreach (var part in doc1.MainDocumentPart.FooterParts)
nextBookmarkId = new[] { nextBookmarkId }
.Concat(part
.GetXDocument()
.Root
.Descendants(W.bookmarkStart)
.Attributes(W.id)
.Select(a => (int)a))
.Max();
if (doc1.MainDocumentPart.FootnotesPart != null)
nextBookmarkId = new[] { nextBookmarkId }
.Concat(doc1
.MainDocumentPart
.FootnotesPart
.GetXDocument()
.Root
.Descendants(W.bookmarkStart)
.Attributes(W.id)
.Select(a => (int)a))
.Max();
if (doc1.MainDocumentPart.EndnotesPart != null)
nextBookmarkId = new[] { nextBookmarkId }
.Concat(doc1
.MainDocumentPart
.EndnotesPart
.GetXDocument()
.Root
.Descendants(W.bookmarkStart)
.Attributes(W.id)
.Select(a => (int)a))
.Max();
nextBookmarkId++;
foreach (var element in doc2.MainDocumentPart.WordprocessingCommentsPart.GetXDocument()
.Root.Elements(W.comment))
element.Attribute(W.id).Value =
(((int)element.Attribute(W.id)) + commentIdIncrease).ToString();
FixIdsInPart(doc2.MainDocumentPart, commentIdIncrease, nextBookmarkId);
foreach (var header in doc2.MainDocumentPart.HeaderParts)
FixIdsInPart(header, commentIdIncrease, nextBookmarkId);
foreach (var footer in doc2.MainDocumentPart.FooterParts)
FixIdsInPart(footer, commentIdIncrease, nextBookmarkId);
FixIdsInPart(doc2.MainDocumentPart.FootnotesPart, commentIdIncrease, nextBookmarkId);
FixIdsInPart(doc2.MainDocumentPart.EndnotesPart, commentIdIncrease, nextBookmarkId);
}
}
}
#if false
todo here are two m:oMath elements that need merged.
<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
<m:r>
<w:rPr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math" />
</w:rPr>
<m:t>W</m:t>
</m:r>
<m:r>
<w:rPr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math" />
</w:rPr>
<m:t>=</m:t>
</m:r>
<m:f>
<m:fPr>
<m:ctrlPr>
<w:rPr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math" />
<w:i />
</w:rPr>
</m:ctrlPr>
</m:fPr>
<m:num>
<m:r>
<w:rPr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math" />
</w:rPr>
<m:t>1</m:t>
</m:r>
</m:num>
<m:den>
<m:r>
<w:rPr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math" />
</w:rPr>
<m:t>μ(1-U)</m:t>
</m:r>
</m:den>
</m:f>
</m:oMath>
<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
<w:commentRangeStart w:id="6" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" />
<m:r>
<w:rPr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math" />
</w:rPr>
<m:t>W</m:t>
</m:r>
<w:commentRangeEnd w:id="6" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" />
<m:r>
<m:rPr>
<m:sty m:val="p" />
</m:rPr>
<w:rPr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:rStyle w:val="CommentReference" />
</w:rPr>
<w:commentReference w:id="6" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" />
</m:r>
<m:r>
<w:rPr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math" />
</w:rPr>
<m:t>=</m:t>
</m:r>
<m:f>
<m:fPr>
<m:ctrlPr>
<w:rPr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math" />
<w:i />
</w:rPr>
</m:ctrlPr>
</m:fPr>
<m:num>
<m:r>
<w:rPr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math" />
</w:rPr>
<m:t>1</m:t>
</m:r>
</m:num>
<m:den>
<m:r>
<w:rPr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math" />
</w:rPr>
<m:t>μ(1-U)</m:t>
</m:r>
</m:den>
</m:f>
</m:oMath>
#endif

View File

@@ -0,0 +1,88 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Xml;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
/// <summary>
/// Provides access to content format operations
/// </summary>
public class ContentFormatAccessor
{
/// <summary>
/// Inserts Xml markup representing format attributes inside a specific paragraph or paragraph run
/// </summary>
/// <param name="document">Document to insert formatting Xml tags</param>
/// <param name="xpathInsertionPoint">Paragraph or paragraph run to set format</param>
/// <param name="content">Formatting tags</param>
public static OpenXmlPowerToolsDocument Insert(WmlDocument doc, string xpathInsertionPoint, string content)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
XDocument xDocument = document.MainDocumentPart.GetXDocument();
XmlDocument xmlMainDocument = new XmlDocument();
xmlMainDocument.Load(xDocument.CreateReader());
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(new NameTable());
namespaceManager.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
XmlNodeList insertionPoints = xmlMainDocument.SelectNodes(xpathInsertionPoint, namespaceManager);
if (insertionPoints.Count == 0)
throw new ArgumentException("The xpath query did not return a valid location.");
foreach (XmlNode insertionPoint in insertionPoints)
{
XmlNode propertiesElement = insertionPoint.SelectSingleNode(@"w:pPr|w:rPr", namespaceManager);
if (insertionPoint.Name == "w:p")
{
// Checks if the rPr or pPr element exists
if (propertiesElement == null)
{
propertiesElement = xmlMainDocument.CreateElement("w", "pPr", namespaceManager.LookupNamespace("w"));
insertionPoint.PrependChild(propertiesElement);
}
}
else if (insertionPoint.Name == "w:r")
{
// Checks if the rPr or pPr element exists
if (propertiesElement == null)
{
propertiesElement = xmlMainDocument.CreateElement("w", "rPr", namespaceManager.LookupNamespace("w"));
insertionPoint.PrependChild(propertiesElement);
}
}
if (propertiesElement != null)
{
propertiesElement.InnerXml += content;
}
else
{
throw new ArgumentException("Specified xpath query result is not a valid location to place a formatting markup");
}
}
XDocument xNewDocument = new XDocument();
using (XmlWriter xWriter = xNewDocument.CreateWriter())
xmlMainDocument.WriteTo(xWriter);
document.MainDocumentPart.PutXDocument(xNewDocument);
}
return streamDoc.GetModifiedDocument();
}
}
}
}

View File

@@ -0,0 +1,155 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Xml.Linq;
namespace OpenXmlPowerTools
{
/// <summary>
/// Provides access to content style operations
/// </summary>
public class ContentStyleAccessor
{
private static XNamespace ns;
private const string newStyleNameSuffix = "_1";
static ContentStyleAccessor()
{
ns = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
}
/// <summary>
/// Gets the tree representing all style hierarchy for a given style
/// </summary>
/// <param name="styleName">Name of style</param>
/// <param name="stylesFile">Styles library</param>
/// <returns>Style tree</returns>
private Collection<XElement> GetStyleHierarchy(string styleName, string stylesFile)
{
Collection<XElement> stylesCollection = new Collection<XElement>();
XDocument xml = new XDocument();
xml = XDocument.Load(stylesFile);
GetStyleDefinition(styleName, xml, stylesCollection);
return stylesCollection;
}
/// <summary>
/// Gets the style definition for the document
/// </summary>
/// <param name="styleName">Style name</param>
/// <param name="xmlStyleDefinitions">Style library</param>
/// <param name="stylesCollection">Styles</param>
public void GetStyleDefinition(string styleName, XDocument xmlStyleDefinitions, Collection<XElement> stylesCollection)
{
XName style = ns + "style";
XName styleId = ns + "styleId";
// create a copy of the xmlstyleDefinition variable so the
// original xml don't be altered
XElement actualStyle =
new XElement(
xmlStyleDefinitions
.Descendants()
.Where(
tag =>
(tag.Name == style) && (tag.Attribute(styleId).Value == styleName)
)
.ToList()
.FirstOrDefault()
);
if (actualStyle != null)
{
// look in the stylesCollection if the style has already been added
IEnumerable<XElement> insertedStyles =
stylesCollection.Where
(
tag =>
(tag.Name == style) && (tag.Attribute(styleId).Value == styleName)
);
// if the style has not been inserted
if (!(insertedStyles.Count() > 0))
{
stylesCollection.Add(actualStyle);
GetStyleDefinition(getLinkStyleId(actualStyle), xmlStyleDefinitions, stylesCollection);
GetStyleDefinition(getNextStyleId(actualStyle), xmlStyleDefinitions, stylesCollection);
GetStyleDefinition(getBasedOnStyleId(actualStyle), xmlStyleDefinitions, stylesCollection);
}
// change the name of the style, so there would be no conflict
// with the original styles definition
actualStyle.Attribute(styleId).Value = actualStyle.Attribute(styleId).Value + newStyleNameSuffix;
}
}
/// <summary>
/// Gets the name of the linked style associated to the given style
/// </summary>
/// <param name="xmlStyle">Style to find link</param>
/// <returns>Linked style name</returns>
public string getLinkStyleId(XElement xmlStyle)
{
XName val = ns + "val";
string linkStyleId = "";
XElement linkStyle = xmlStyle.Descendants(ns + "link").FirstOrDefault();
if (linkStyle != null)
{
linkStyleId = linkStyle.Attribute(val).Value;
// change the name of the attribute, because the new added style is being renamed
linkStyle.Attribute(val).Value = linkStyle.Attribute(val).Value + newStyleNameSuffix;
}
return linkStyleId;
}
/// <summary>
/// Gets the name of the style tagged as 'next' associated to the given style
/// </summary>
/// <param name="xmlStyle">Style to find 'next' element</param>
/// <returns>Name of style tagged as 'next</returns>
public string getNextStyleId(XElement xmlStyle)
{
XName val = ns + "val";
string nextStyleId = "";
XElement nextStyle = xmlStyle.Descendants(ns + "next").FirstOrDefault();
if (nextStyle != null)
{
nextStyleId = nextStyle.Attribute(val).Value;
// change the name of the attribute, because the new added style is being renamed
nextStyle.Attribute(val).Value = nextStyle.Attribute(val).Value + newStyleNameSuffix;
}
return nextStyleId;
}
/// <summary>
/// Get the name of the style tagged as 'basedOn' associated to the given style
/// </summary>
/// <param name="xmlStyle">Style to find 'basedOn' element</param>
/// <returns>Name of style tagged as 'basedOn'</returns>
public string getBasedOnStyleId(XElement xmlStyle)
{
XName val = ns + "val";
string basedOnStyleId = "";
XElement basedOnStyle = xmlStyle.Descendants(ns + "basedOn").FirstOrDefault();
if (basedOnStyle != null)
{
basedOnStyleId = basedOnStyle.Attribute(val).Value;
// change the name of the attribute, because the new added style is being renamed
basedOnStyle.Attribute(val).Value = basedOnStyle.Attribute(val).Value + newStyleNameSuffix;
}
return basedOnStyleId;
}
}
}

View File

@@ -0,0 +1,67 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Linq;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
/// <summary>
/// Performs operations on document custom xml
/// </summary>
public class CustomXmlAccessor{
/// <summary>
/// Searches for a custom Xml part with a given name
/// </summary>
/// <param name="xmlPartName">Name of custom Xml part</param>
/// <returns>XDocument with customXml part loaded</returns>
public static XDocument Find(WmlDocument doc, string xmlPartName)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
WordprocessingDocument document = streamDoc.GetWordprocessingDocument();
string partName = "/" + xmlPartName;
var customXmlPart =
document.MainDocumentPart.CustomXmlParts.Where(
t => t.Uri.OriginalString.EndsWith(partName, System.StringComparison.OrdinalIgnoreCase)
).FirstOrDefault();
if (customXmlPart == null)
throw new ArgumentException("Part name '" + xmlPartName + "' not found.");
return customXmlPart.GetXDocument();
}
}
/// <summary>
/// Replaces a previously existing customXml part by another one
/// </summary>
/// <param name="customXmlDocument">XDocument of part to replace inside the document package</param>
/// <param name="partNameOnly">Name of the part.</param>
public static OpenXmlPowerToolsDocument SetDocument(WmlDocument doc, XDocument customXmlDocument, string partNameOnly)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
string partName = "/" + partNameOnly;
var customXmlPart = document.MainDocumentPart.CustomXmlParts.Where(
t => t.Uri.OriginalString.EndsWith(partName, System.StringComparison.OrdinalIgnoreCase)
).FirstOrDefault();
if (customXmlPart == null)
customXmlPart = document.MainDocumentPart.AddCustomXmlPart(CustomXmlPartType.CustomXml);
customXmlPart.PutXDocument(customXmlDocument);
}
return streamDoc.GetModifiedDocument();
}
}
}
}

View File

@@ -0,0 +1,104 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using System.Collections.ObjectModel;
using System.IO.Packaging;
namespace OpenXmlPowerTools
{
public class DigitalSignatureAccessor
{
public static OpenXmlPowerToolsDocument Insert(OpenXmlPowerToolsDocument doc, IEnumerable<string> certificateList)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (Package package = streamDoc.GetPackage())
{
foreach (string digitalCertificate in certificateList)
{
X509Certificate x509Certificate = X509Certificate2.CreateFromCertFile(digitalCertificate);
PackageDigitalSignatureManager digitalSigntaureManager = new PackageDigitalSignatureManager(package);
digitalSigntaureManager.CertificateOption = CertificateEmbeddingOption.InSignaturePart;
System.Collections.Generic.List<Uri> partsToSign = new System.Collections.Generic.List<Uri>();
//Adds each part to the list, except relationships parts.
foreach (PackagePart openPackagePart in package.GetParts())
{
if (!PackUriHelper.IsRelationshipPartUri(openPackagePart.Uri))
partsToSign.Add(openPackagePart.Uri);
}
List<PackageRelationshipSelector> relationshipSelectors = new List<PackageRelationshipSelector>();
//Creates one selector for each package-level relationship, based on id
foreach (PackageRelationship relationship in package.GetRelationships())
{
PackageRelationshipSelector relationshipSelector =
new PackageRelationshipSelector(relationship.SourceUri, PackageRelationshipSelectorType.Id, relationship.Id);
relationshipSelectors.Add(relationshipSelector);
}
digitalSigntaureManager.Sign(partsToSign, x509Certificate, relationshipSelectors);
}
}
return streamDoc.GetModifiedDocument();
}
}
/// <summary>
/// Tests a Digital Signature from a package
/// </summary>
/// <returns>Digital signatures list</returns>
public static Collection<string> GetList(OpenXmlPowerToolsDocument doc)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
// Creates the PackageDigitalSignatureManager
PackageDigitalSignatureManager digitalSignatureManager = new PackageDigitalSignatureManager(streamDoc.GetPackage());
// Verifies the collection of certificates in the package
Collection<string> digitalSignatureDescriptions = new Collection<string>();
ReadOnlyCollection<PackageDigitalSignature> digitalSignatures = digitalSignatureManager.Signatures;
if (digitalSignatures.Count > 0)
{
foreach (PackageDigitalSignature signature in digitalSignatures)
{
if (PackageDigitalSignatureManager.VerifyCertificate(signature.Signer) != X509ChainStatusFlags.NoError)
{
digitalSignatureDescriptions.Add(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Signature: {0} ({1})", signature.Signer.Subject, PackageDigitalSignatureManager.VerifyCertificate(signature.Signer)));
}
else
digitalSignatureDescriptions.Add("Signature: " + signature.Signer.Subject);
}
}
else
{
digitalSignatureDescriptions.Add("No digital signatures found");
}
return digitalSignatureDescriptions;
}
}
/// <summary>
/// RemoveAll
/// </summary>
public static OpenXmlPowerToolsDocument RemoveAll(OpenXmlPowerToolsDocument doc)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (Package package = streamDoc.GetPackage())
{
// Creates the PackageDigitalSignatureManager
PackageDigitalSignatureManager digitalSignatureManager = new PackageDigitalSignatureManager(package);
digitalSignatureManager.RemoveAllSignatures();
}
return streamDoc.GetModifiedDocument();
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,346 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
public class DocumentComparerInternalException : Exception
{
public DocumentComparerInternalException(string message) : base(message) { }
}
public static class DocumentComparer
{
private enum RunElementType
{
WordRun,
MathRun,
Other
};
private enum RunChildElementType
{
WordTextElement,
MathTextElement,
Other
};
private static bool CompareRunCollections(IEnumerable<XElement> runCollection1,
IEnumerable<XElement> runCollection2)
{
var runChildElementCollection1 = runCollection1
.Elements()
.Where(e => e.Name != W.commentRangeStart &&
e.Name != W.commentRangeEnd &&
e.Name != W.commentReference &&
e.Name != W.rPr &&
e.Name != W.proofErr &&
e.Name != M.sty &&
e.Name != M.rPr)
.GroupAdjacent(e =>
{
if (e.Name == W.t)
return RunChildElementType.WordTextElement;
if (e.Name == M.t)
return RunChildElementType.MathTextElement;
return RunChildElementType.Other;
});
var runChildElementCollection2 = runCollection2
.Elements()
.Where(e => e.Name != W.commentRangeStart &&
e.Name != W.commentRangeEnd &&
e.Name != W.commentReference &&
e.Name != W.rPr &&
e.Name != W.proofErr &&
e.Name != M.sty &&
e.Name != M.rPr)
.GroupAdjacent(e =>
{
if (e.Name == W.t)
return RunChildElementType.WordTextElement;
if (e.Name == M.t)
return RunChildElementType.MathTextElement;
return RunChildElementType.Other;
});
#if false
foreach (var item in runChildElementCollection1)
{
Console.WriteLine(item.Key);
foreach (var i2 in item)
{
Console.WriteLine(i2.Name.LocalName);
}
Console.WriteLine();
}
Console.WriteLine();
foreach (var item in runChildElementCollection2)
{
Console.WriteLine(item.Key);
foreach (var i2 in item)
{
Console.WriteLine(i2.Name.LocalName);
}
Console.WriteLine();
}
Environment.Exit(0);
#endif
bool different = runChildElementCollection1
.Zip(runChildElementCollection2, (c1, c2) =>
{
if (c1.Key != c2.Key)
return false;
switch (c1.Key)
{
case RunChildElementType.WordTextElement:
case RunChildElementType.MathTextElement:
string string1 = c1.Select(t => (string)t).StringConcatenate();
string string2 = c2.Select(t => (string)t).StringConcatenate();
if (string1 == string2)
return true;
else
return false;
case RunChildElementType.Other:
bool d = c1
.Zip(c2, (e1, e2) => new { E1 = e1, E2 = e2 })
.Select(z => CompareOpenXmlElements(z.E1, z.E2))
.Any(b => b == false);
if (d == true)
return false;
else
return true;
};
throw new DocumentComparerInternalException(
"Should not have reached this code");
})
.Any(b => b == false);
if (different == true)
return false;
else
return true;
}
private static bool CompareOtherCollections(IEnumerable<XElement> collection1,
IEnumerable<XElement> collection2)
{
bool different = collection1
.Zip(collection2, (e1, e2) => new { E1 = e1, E2 = e2 })
.Select(z => CompareOpenXmlElements(z.E1, z.E2))
.Any(b => b == false);
if (different == true)
return false;
else
return true;
}
private static bool CompareElementsWithRuns(XElement element1, XElement element2)
{
// todo why is hyperlink and fldChar in the following list???
var groupedCollection1 = element1
.Elements()
.Where(e => e.Name != W.commentRangeStart &&
e.Name != W.commentRangeEnd &&
e.Name != W.rsid &&
e.Name != W.proofErr &&
e.Name != W.fldChar &&
e.Name != W.hyperlink &&
e.Name != W.bookmarkStart &&
e.Name != W.bookmarkEnd)
.GroupAdjacent(e =>
{
if (e.Name == W.r)
return RunElementType.WordRun;
if (e.Name == M.r)
return RunElementType.MathRun;
return RunElementType.Other;
});
var groupedCollection2 = element2
.Elements()
.Where(e => e.Name != W.commentRangeStart &&
e.Name != W.commentRangeEnd &&
e.Name != W.rsid &&
e.Name != W.proofErr &&
e.Name != W.fldChar &&
e.Name != W.hyperlink &&
e.Name != W.bookmarkStart &&
e.Name != W.bookmarkEnd)
.GroupAdjacent(e =>
{
if (e.Name == W.r)
return RunElementType.WordRun;
if (e.Name == M.r)
return RunElementType.MathRun;
return RunElementType.Other;
});
if (groupedCollection1.Count() != groupedCollection2.Count())
{
#if false
// If this test returns false for a document that you think is erroneous,
// the following will give clues to the markup that may need to be ignored, or
// the markup that indicates that the documents are different.
foreach (var item in groupedCollection1)
{
Console.WriteLine(item.Key);
foreach (var item2 in item)
{
Console.WriteLine(item2.Name.LocalName);
}
Console.WriteLine();
}
Console.WriteLine("==================");
foreach (var item in groupedCollection2)
{
Console.WriteLine(item.Key);
foreach (var item2 in item)
{
Console.WriteLine(item2.Name.LocalName);
}
Console.WriteLine();
}
Environment.Exit(0);
#endif
return false;
}
bool different = groupedCollection1
.Zip(groupedCollection2, (c1, c2) =>
{
if (c1.Key != c2.Key)
return false;
switch (c1.Key)
{
case RunElementType.WordRun:
case RunElementType.MathRun:
return CompareRunCollections(c1, c2);
case RunElementType.Other:
return CompareOtherCollections(c1, c2);
};
throw new DocumentComparerInternalException(
"Should not have reached this code");
})
.Any(b => b == false);
if (different == true)
return false;
else
return true;
}
// returns true if the elements are the same, otherwise false.
private static bool CompareOpenXmlElements(XElement element1, XElement element2)
{
if (element1.Name != element2.Name)
return false;
if (element1
.Elements()
.Where(e => e.Name == W.r || e.Name == M.r)
.Any())
{
bool rValue = CompareElementsWithRuns(element1, element2);
// todo fix
if (rValue == true)
return true;
else
return false;
}
if (element1.Nodes().OfType<XText>().Any() &&
!element1.HasElements)
{
if (element1.Value == element2.Value)
return true;
else
return false;
}
if (element1.IsEmpty && element2.IsEmpty)
return true;
var c1 = element1
.Elements()
.Where(e => e.Name != W.commentRangeStart &&
e.Name != W.commentRangeEnd &&
e.Name != W.proofErr &&
e.Name != W.rsid);
var c2 = element2
.Elements()
.Where(e => e.Name != W.commentRangeStart &&
e.Name != W.commentRangeEnd &&
e.Name != W.proofErr &&
e.Name != W.rsid);
if (c1.Count() != c2.Count())
return false;
var different = c1
.Zip(c2, (e1, e2) => new { E1 = e1, E2 = e2 })
.Select(p => CompareOpenXmlElements(p.E1, p.E2))
.Any(b => b == false);
if (different == true)
return false;
else
return true;
}
// todo
// we want overload for this that takes WmlDocument, or whatever new class is.
// also want ability to specify multiple options - a settings object - compare headers, footers, etc.
//
// Returns true if docs are the same, otherwise false.
public static bool CompareDocuments(WordprocessingDocument doc1, WordprocessingDocument doc2)
{
XDocument doc1XDoc = doc1.MainDocumentPart.GetXDocument();
XDocument doc2XDoc = doc2.MainDocumentPart.GetXDocument();
if (CompareOpenXmlElements(doc1XDoc.Root, doc2XDoc.Root) == false)
return false;
// for the current use of this class, only need to compare the main document parts.
#if false
if (doc1.MainDocumentPart.HeaderParts.Count() != doc2.MainDocumentPart.HeaderParts.Count())
return false;
foreach (var pair in doc1
.MainDocumentPart
.HeaderParts
.Zip(doc2.MainDocumentPart.HeaderParts, (d1, d2) =>
new
{
Doc1Header = d1,
Doc2Header = d2,
}))
{
if (CompareOpenXmlElements(pair.Doc1Header.GetXDocument().Root,
pair.Doc2Header.GetXDocument().Root) == false)
return false;
}
if (doc1.MainDocumentPart.FooterParts.Count() != doc2.MainDocumentPart.FooterParts.Count())
return false;
foreach (var pair in doc1
.MainDocumentPart
.FooterParts
.Zip(doc2.MainDocumentPart.FooterParts, (d1, d2) =>
new
{
Doc1Footer = d1,
Doc2Footer = d2,
}))
{
if (CompareOpenXmlElements(pair.Doc1Footer.GetXDocument().Root,
pair.Doc2Footer.GetXDocument().Root) == false)
return false;
}
if ((doc1.MainDocumentPart.FootnotesPart == null) != (doc2.MainDocumentPart.FootnotesPart == null))
return false;
if (doc1.MainDocumentPart.FootnotesPart != null)
{
if (CompareOpenXmlElements(doc1.MainDocumentPart.FootnotesPart.GetXDocument().Root,
doc2.MainDocumentPart.FootnotesPart.GetXDocument().Root) == false)
return false;
}
if ((doc1.MainDocumentPart.EndnotesPart == null) != (doc2.MainDocumentPart.EndnotesPart == null))
return false;
if (doc1.MainDocumentPart.EndnotesPart != null)
{
if (CompareOpenXmlElements(doc1.MainDocumentPart.EndnotesPart.GetXDocument().Root,
doc2.MainDocumentPart.EndnotesPart.GetXDocument().Root) == false)
return false;
}
#endif
return true;
}
}
}

View File

@@ -0,0 +1,218 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.Linq;
using System.Xml.Linq;
using System.Collections.Generic;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
public enum FooterType
{
Default,
First,
Even
}
/// <summary>
/// Provides access to footer operations
/// </summary>
public class FooterAccessor
{
private static XNamespace ns;
private static XNamespace relationshipns;
static FooterAccessor()
{
ns = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
relationshipns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
}
/// <summary>
/// Elements tagged as section properties
/// </summary>
/// <returns>IEnumerable&lt;XElement&gt; containing all the section properties elements found it in the document</returns>
private static IEnumerable<XElement> SectionPropertiesElements(WordprocessingDocument document)
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
IEnumerable<XElement> results =
mainDocument
.Descendants(ns + "p")
.Elements(ns + "pPr")
.Elements(ns + "sectPr");
if (results.Count() == 0)
results = mainDocument.Root.Elements(ns + "body").Elements(ns + "sectPr");
return results;
}
/// <summary>
/// Footer reference nodes inside the document
/// </summary>
/// <param name="type">The footer part type</param>
/// <returns>XElement containing the part reference in the document</returns>
private static XElement GetFooterReference(WordprocessingDocument document, FooterType type, int sectionIndex)
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
XName footerReferenceTag = ns + "footerReference";
XName typeTag = ns + "type";
string typeName = "";
switch (type)
{
case FooterType.First: typeName = "first";
break;
case FooterType.Even: typeName = "even";
break;
case FooterType.Default: typeName = "default";
break;
}
XElement sectionPropertyElement = SectionPropertiesElements(document).Skip(sectionIndex).FirstOrDefault();
if (sectionPropertyElement != null)
{
return sectionPropertyElement.Descendants().Where(tag => (tag.Name == footerReferenceTag) && (tag.Attribute(typeTag).Value == typeName)).FirstOrDefault();
}
return null;
}
/// <summary>
/// Get the specified footer from the document
/// </summary>
/// <param name="type">The footer part type</param>
/// <returns>the XDocument containing the footer</returns>
public static XDocument GetFooter(WmlDocument doc, FooterType type, int sectionIndex)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
OpenXmlPart footer = GetFooterPart(document, type, sectionIndex);
if (footer != null)
return footer.GetXDocument();
return null;
}
}
/// <summary>
/// The specified footer part from the document
/// </summary>
/// <param name="type">The footer part type</param>
/// <returns>A OpenXmlPart containing the footer part</returns>
public static OpenXmlPart GetFooterPart(WordprocessingDocument document, FooterType type, int sectionIndex)
{
// look in the section properties of the main document part, the respective footer
// needed to extract
XElement footerReferenceElement = GetFooterReference(document, type, sectionIndex);
if (footerReferenceElement != null)
{
// get the relation id of the footer part to extract from the document
string relationshipId = footerReferenceElement.Attribute(relationshipns + "id").Value;
return document.MainDocumentPart.GetPartById(relationshipId);
}
return null;
}
/// <summary>
/// Removes the specified footer in the document
/// </summary>
/// <param name="type">The footer part type</param>
public static void RemoveFooter(WmlDocument doc, FooterType type, int sectionIndex)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
OpenXmlPart footerPart = GetFooterPart(document, type, sectionIndex);
footerPart.RemovePart();
}
}
/// <summary>
/// Set a new footer in a document
/// </summary>
/// <param name="footer">XDocument containing the footer to add in the document</param>
/// <param name="type">The footer part type</param>
public static OpenXmlPowerToolsDocument SetFooter(WmlDocument doc, XDocument footer, FooterType type, int sectionIndex)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
// Removes the reference in the document.xml and the footer part if those already
// exist
XElement footerReferenceElement = GetFooterReference(document, type, sectionIndex);
if (footerReferenceElement != null)
{
GetFooterPart(document, type, sectionIndex).RemovePart();
footerReferenceElement.Remove();
}
// Add the new footer
FooterPart footerPart = document.MainDocumentPart.AddNewPart<FooterPart>();
footerPart.PutXDocument(footer);
// If the document does not have a property section a new one must be created
if (SectionPropertiesElements(document).Count() == 0)
{
AddDefaultSectionProperties(document);
}
// Creates the relationship of the footer inside the section properties in the document
string relID = document.MainDocumentPart.GetIdOfPart(footerPart);
string kindName = "";
switch ((FooterType)type)
{
case FooterType.First:
kindName = "first";
break;
case FooterType.Even:
kindName = "even";
break;
case FooterType.Default:
kindName = "default";
break;
}
XElement sectionPropertyElement = SectionPropertiesElements(document).Skip(sectionIndex).FirstOrDefault();
if (sectionPropertyElement != null)
{
sectionPropertyElement.Add(
new XElement(ns + "footerReference",
new XAttribute(ns + "type", kindName),
new XAttribute(relationshipns + "id", relID)));
if (sectionPropertyElement.Element(ns + "titlePg") == null)
sectionPropertyElement.Add(
new XElement(ns + "titlePg")
);
}
document.MainDocumentPart.PutXDocument();
// add in the settings part the EvendAndOddHeaders. this element
// allow to see the odd and even footers and headers in the document.
SettingAccessor.AddEvenAndOddHeadersElement(document);
}
return streamDoc.GetModifiedDocument();
}
}
/// <summary>
/// Adds a default sectPr element into the main document
/// </summary>
private static void AddDefaultSectionProperties(WordprocessingDocument document)
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
mainDocument.Descendants(ns + "body").First().Add(
new XElement(ns + "sectPr")
);
}
}
}

View File

@@ -0,0 +1,278 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.Linq;
using System.Xml.Linq;
using System.Collections.Generic;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
public enum HeaderType
{
Default,
First,
Even
}
/// <summary>
/// Provides access to header operations
/// </summary>
public class HeaderAccessor
{
private const string defaultHeaderType = "default";
private static XNamespace ns;
private static XNamespace relationshipns;
private static XNamespace officens;
private static XNamespace vmlns;
private static XNamespace wordns;
static HeaderAccessor() {
ns = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
relationshipns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
officens = "urn:schemas-microsoft-com:office:office";
vmlns = "urn:schemas-microsoft-com:vml";
wordns = "urn:schemas-microsoft-com:office:word";
}
/// <summary>
/// Elements tagged as section properties
/// </summary>
/// <returns>IEnumerable&lt;XElement&gt; containing all the section properties elements found it in the document</returns>
private static IEnumerable<XElement> SectionPropertiesElements(WordprocessingDocument document)
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
IEnumerable<XElement> results =
mainDocument
.Descendants(ns + "p")
.Elements(ns + "pPr")
.Elements(ns + "sectPr");
if (results.Count() == 0)
results = mainDocument.Root.Elements(ns + "body").Elements(ns + "sectPr");
return results;
}
/// <summary>
/// Adds a new header reference in the section properties
/// </summary>
/// <param name="type">The header part type</param>
/// <param name="headerPartId">the header part id</param>
public static void AddHeaderReference(WordprocessingDocument document, HeaderType type, string headerPartId, int sectionIndex)
{
// If the document does not have a property section a new one must be created
if (SectionPropertiesElements(document).Count() == 0)
{
AddDefaultSectionProperties(document);
}
string typeName = "";
switch ((HeaderType)type)
{
case HeaderType.First:
typeName = "first";
break;
case HeaderType.Even:
typeName = "even";
break;
case HeaderType.Default:
typeName = "default";
break;
}
XElement sectionPropertyElement = SectionPropertiesElements(document).Skip(sectionIndex).FirstOrDefault();
if (sectionPropertyElement != null)
{
sectionPropertyElement.Add(
new XElement(ns + "headerReference",
new XAttribute(ns + "type", typeName),
new XAttribute(relationshipns + "id", headerPartId)));
if (sectionPropertyElement.Element(ns + "titlePg") == null)
sectionPropertyElement.Add(
new XElement(ns + "titlePg")
);
}
document.MainDocumentPart.PutXDocument();
}
/// <summary>
/// Adds a new header part in the document
/// </summary>
/// <param name="type">The footer part type</param>
/// <returns>A XDocument contaning the added header</returns>
public static XDocument AddNewHeader(WordprocessingDocument document, HeaderType type)
{
// Creates the new header part
HeaderPart newHeaderPart = document.MainDocumentPart.AddNewPart<HeaderPart>();
XDocument emptyHeader = CreateEmptyHeaderDocument();
newHeaderPart.PutXDocument(emptyHeader);
string newHeaderPartId = document.MainDocumentPart.GetIdOfPart(newHeaderPart);
AddHeaderReference(document, type, newHeaderPartId, 0);
return emptyHeader;
}
/// <summary>
/// Creates an empty header document
/// </summary>
/// <returns>A XDocument containing the xml of an empty header part </returns>
private static XDocument CreateEmptyHeaderDocument()
{
return new XDocument(
new XElement(ns + "hdr",
new XAttribute(XNamespace.Xmlns + "w", ns),
new XAttribute(XNamespace.Xmlns + "r", relationshipns),
new XAttribute(XNamespace.Xmlns + "o", officens),
new XAttribute(XNamespace.Xmlns + "v", vmlns),
new XAttribute(XNamespace.Xmlns + "w10", wordns)
)
);
}
/// <summary>
/// Header reference nodes inside the document
/// </summary>
/// <param name="type">The header part type</param>
/// <returns>XElement containing the part reference in the document</returns>
public static XElement GetHeaderReference(WordprocessingDocument document, HeaderType type, int sectionIndex)
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
XName headerReferenceTag = ns + "headerReference";
XName typeTag = ns + "type";
string typeName = "";
switch (type)
{
case HeaderType.First: typeName = "first";
break;
case HeaderType.Even: typeName = "even";
break;
case HeaderType.Default: typeName = "default";
break;
}
XElement sectionPropertyElement = SectionPropertiesElements(document).Skip(sectionIndex).FirstOrDefault();
if (sectionPropertyElement != null)
{
return sectionPropertyElement.Descendants().Where(tag => (tag.Name == headerReferenceTag) && (tag.Attribute(typeTag).Value == typeName)).FirstOrDefault();
}
return null;
}
/// <summary>
/// Get the specified header from the document
/// </summary>
/// <param name="type">The header part type</param>
/// <returns>A XDocument containing the header</returns>
public static XDocument GetHeader(WmlDocument doc, HeaderType type, int sectionIndex)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
OpenXmlPart header = GetHeaderPart(document, type, sectionIndex);
if (header != null)
return header.GetXDocument();
return null;
}
}
public static XDocument GetHeader(WordprocessingDocument document, HeaderType type, int sectionIndex)
{
OpenXmlPart header = GetHeaderPart(document, type, sectionIndex);
if (header != null)
return header.GetXDocument();
return null;
}
/// <summary>
/// The specified header part from the document
/// </summary>
/// <param name="type">The header part type</param>
/// <returns>A OpenXmlPart containing the header part</returns>
public static OpenXmlPart GetHeaderPart(WordprocessingDocument document, HeaderType type, int sectionIndex)
{
// look in the section properties of the main document part, the respective Header
// needed to extract
XElement headerReferenceElement = GetHeaderReference(document, type, sectionIndex);
if (headerReferenceElement != null)
{
// get the relation id of the Header part to extract from the document
string relationId = headerReferenceElement.Attribute(relationshipns + "id").Value;
return document.MainDocumentPart.GetPartById(relationId);
}
else
return null;
}
/// <summary>
/// Removes the specified header in the document
/// </summary>
/// <param name="type">The header part type</param>
public void RemoveHeader(WmlDocument doc, HeaderType type, int sectionIndex)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
OpenXmlPart headerPart = GetHeaderPart(document, type, sectionIndex);
headerPart.RemovePart();
}
}
/// <summary>
/// Set a new header in a document
/// </summary>
/// <param name="header">XDocument containing the header to add in the document</param>
/// <param name="type">The header part type</param>
public static OpenXmlPowerToolsDocument SetHeader(WmlDocument doc, XDocument header, HeaderType type, int sectionIndex)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
// Removes the reference in the document.xml and the header part if those already
// exist
XElement headerReferenceElement = GetHeaderReference(document, type, sectionIndex);
if (headerReferenceElement != null)
{
GetHeaderPart(document, type, sectionIndex).RemovePart();
headerReferenceElement.Remove();
}
// Add the new header
HeaderPart headerPart = document.MainDocumentPart.AddNewPart<HeaderPart>();
headerPart.PutXDocument(header);
// Creates the relationship of the header inside the section properties in the document
string relID = document.MainDocumentPart.GetIdOfPart(headerPart);
AddHeaderReference(document, type, relID, sectionIndex);
// add in the settings part the EvendAndOddHeaders. this element
// allow to see the odd and even headers and headers in the document.
SettingAccessor.AddEvenAndOddHeadersElement(document);
}
return streamDoc.GetModifiedDocument();
}
}
/// <summary>
/// Adds a default sectPr element into the main document
/// </summary>
private static void AddDefaultSectionProperties(WordprocessingDocument document)
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
mainDocument.Element(ns + "body").Add(
new XElement(ns + "sectPr")
);
}
}
}

View File

@@ -0,0 +1,841 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2010.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license
can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
public partial class WmlDocument : OpenXmlPowerToolsDocument
{
public XElement ConvertToHtml(HtmlConverterSettings htmlConverterSettings, Func<ImageInfo, XElement> imageHandler)
{
return HtmlConverter.ConvertToHtml(this, htmlConverterSettings, imageHandler);
}
public XElement ConvertToHtml(HtmlConverterSettings htmlConverterSettings)
{
return HtmlConverter.ConvertToHtml(this, htmlConverterSettings);
}
}
public class HtmlConverterSettings
{
public string PageTitle;
public string CssClassPrefix;
public string Css;
public bool ConvertFormatting;
}
public static class Xhtml
{
public static XNamespace xhtml = "http://www.w3.org/1999/xhtml";
public static XName html = xhtml + "html";
public static XName head = xhtml + "head";
public static XName title = xhtml + "title";
public static XName body = xhtml + "body";
public static XName p = xhtml + "p";
public static XName h1 = xhtml + "h1";
public static XName h2 = xhtml + "h2";
public static XName A = xhtml + "A";
public static XName b = xhtml + "b";
public static XName table = xhtml + "table";
public static XName tr = xhtml + "tr";
public static XName td = xhtml + "td";
public static XName meta = xhtml + "meta";
public static XName style = xhtml + "style";
public static XName br = xhtml + "br";
public static XName img = xhtml + "img";
public static XName span = xhtml + "span";
}
public static class HtmlNoNamespace
{
public static XName href = "href";
public static XName border = "border";
public static XName http_equiv = "http-equiv";
public static XName content = "content";
public static XName name = "name";
public static XName width = "width";
public static XName height = "height";
public static XName src = "src";
public static XName style = "style";
public static XName alt = "alt";
public static XName id = "id";
public static XName descr = "descr";
public static XName _class = "class";
}
public class ImageInfo
{
public Bitmap Bitmap;
public XAttribute ImgStyleAttribute;
public string ContentType;
public XElement DrawingElement;
public string AltText;
public static int EmusPerInch = 914400;
public static int EmusPerCm = 360000;
}
public static class HtmlConverter
{
private static Dictionary<char, string> EntityMap = null;
public class InvalidSettingsException : Exception
{
public InvalidSettingsException(string message) : base(message) { }
}
private static XElement ProcessImage(WordprocessingDocument wordDoc,
XElement element, Func<ImageInfo, XElement> imageHandler)
{
if (element.Name == W.drawing)
{
XElement containerElement = element.Elements()
.Where(e => e.Name == WP.inline || e.Name == WP.anchor)
.FirstOrDefault();
if (containerElement != null)
{
int? extentCx = (int?)containerElement.Elements(WP.extent)
.Attributes(NoNamespace.cx).FirstOrDefault();
int? extentCy = (int?)containerElement.Elements(WP.extent)
.Attributes(NoNamespace.cy).FirstOrDefault();
string altText = (string)containerElement.Elements(WP.docPr)
.Attributes(NoNamespace.descr).FirstOrDefault();
if (altText == null)
altText = (string)containerElement.Elements(WP.docPr)
.Attributes(NoNamespace.name).FirstOrDefault();
if (altText == null)
altText = "";
XElement blipFill = containerElement.Elements(A.graphic)
.Elements(A.graphicData)
.Elements(Pic._pic).Elements(Pic.blipFill).FirstOrDefault();
if (blipFill != null)
{
string imageRid = (string)blipFill.Elements(A.blip).Attributes(R.embed)
.FirstOrDefault();
ImagePart imagePart = (ImagePart)wordDoc.MainDocumentPart
.GetPartById(imageRid);
string contentType = imagePart.ContentType;
if (contentType == "image/png" ||
contentType == "image/gif" ||
contentType == "image/tiff" ||
contentType == "image/jpeg")
{
using (Stream partStream = imagePart.GetStream())
using (Bitmap bitmap = new Bitmap(partStream))
{
if (extentCx != null && extentCy != null)
{
ImageInfo imageInfo = new ImageInfo()
{
Bitmap = bitmap,
ImgStyleAttribute = new XAttribute(HtmlNoNamespace.style,
string.Format("width: {0}in; height: {1}in",
(float)extentCx / (float)ImageInfo.EmusPerInch,
(float)extentCy / (float)ImageInfo.EmusPerInch)),
ContentType = contentType,
DrawingElement = element,
AltText = altText,
};
return imageHandler(imageInfo);
}
ImageInfo imageInfo2 = new ImageInfo()
{
Bitmap = bitmap,
ContentType = contentType,
DrawingElement = element,
AltText = altText,
};
return imageHandler(imageInfo2);
};
}
}
}
}
if (element.Name == W.pict)
{
string imageRid = (string)element.Elements(VML.shape)
.Elements(VML.imagedata).Attributes(R.id).FirstOrDefault();
string style = (string)element.Elements(VML.shape)
.Attributes(HtmlNoNamespace.style).FirstOrDefault();
if (imageRid != null)
{
try
{
ImagePart imagePart = (ImagePart)wordDoc.MainDocumentPart
.GetPartById(imageRid);
string contentType = imagePart.ContentType;
if (contentType == "image/png" ||
contentType == "image/gif" ||
contentType == "image/tiff" ||
contentType == "image/jpeg")
{
//string style = element.
using (Stream partStream = imagePart.GetStream())
using (Bitmap bitmap = new Bitmap(partStream))
{
ImageInfo imageInfo = new ImageInfo()
{
Bitmap = bitmap,
ContentType = contentType,
DrawingElement = element,
};
if (style != null)
{
float? widthInPoints = null;
float? heightInPoints = null;
string[] tokens = style.Split(';');
var widthString = tokens
.Select(t => new
{
Name = t.Split(':').First(),
Value = t.Split(':').Skip(1)
.Take(1).FirstOrDefault(),
})
.Where(p => p.Name == "width")
.Select(p => p.Value)
.FirstOrDefault();
if (widthString != null &&
widthString.Substring(widthString.Length - 2) == "pt")
{
float w;
if (float.TryParse(widthString.Substring(0,
widthString.Length - 2), out w))
widthInPoints = w;
}
var heightString = tokens
.Select(t => new
{
Name = t.Split(':').First(),
Value = t.Split(':').Skip(1).Take(1).FirstOrDefault(),
})
.Where(p => p.Name == "height")
.Select(p => p.Value)
.FirstOrDefault();
if (heightString != null &&
heightString.Substring(heightString.Length - 2) == "pt")
{
float h;
if (float.TryParse(heightString.Substring(0,
heightString.Length - 2), out h))
heightInPoints = h;
}
if (widthInPoints != null && heightInPoints != null)
imageInfo.ImgStyleAttribute = new XAttribute(
HtmlNoNamespace.style, string.Format(
"width: {0}pt; height: {1}pt",
widthInPoints, heightInPoints));
}
return imageHandler(imageInfo);
};
}
}
catch (ArgumentOutOfRangeException)
{
return null;
}
}
}
return null;
}
private static object ConvertEntities(string text)
{
if (text == null)
return null;
object o = text.ToCharArray()
.GroupAdjacent((char c) =>
{
if (c == 0xf0b7 ||
c == 0xf0a7 ||
c == 0xf076 ||
c == 0xf0d8 ||
c == 0xf0a8 ||
c == 0xf0fc ||
c == 0xf0e0 ||
c == 0xf0b2)
return "bull";
if (c >= 0xf000)
return "loz";
if (c >= 128)
{
string entity;
if (EntityMap.TryGetValue(c, out entity))
return entity;
}
return "-";
})
.Select(g =>
{
if (g.Key != "-")
return (object)(g.Select(c => new XEntity(g.Key)));
return new XText(g.Aggregate(new StringBuilder(),
(s, i) => s.Append(i),
s => s.ToString()));
});
return o;
}
private static object ConvertToHtmlTransform(WordprocessingDocument wordDoc,
HtmlConverterSettings settings, XNode node,
Func<ImageInfo, XElement> imageHandler)
{
XElement element = node as XElement;
if (element != null)
{
if (element.Name == W.document)
return new XElement(Xhtml.html,
new XElement(Xhtml.head,
new XElement(Xhtml.meta,
new XAttribute(HtmlNoNamespace.http_equiv, "Content-Type"),
new XAttribute(HtmlNoNamespace.content,
"text/html; charset=windows-1252")),
new XElement(Xhtml.meta,
new XAttribute(HtmlNoNamespace.name, "Generator"),
new XAttribute(HtmlNoNamespace.content,
"PowerTools for Open XML")),
settings.PageTitle != null ? new XElement(Xhtml.title,
settings.PageTitle) : null,
settings.Css != null ? new XElement(Xhtml.style,
new XComment(Environment.NewLine +
settings.Css + Environment.NewLine)) : null
),
element.Elements().Select(e => ConvertToHtmlTransform(
wordDoc, settings, e, imageHandler))
);
// Transform the w:body element to the XHTML h:body element.
if (element.Name == W.body)
return new XElement(Xhtml.body,
element.Elements().Select(e => ConvertToHtmlTransform(
wordDoc, settings, e, imageHandler)));
// Transform every paragraph with a style that has paragraph properties
// that has an outline level into the same level of heading. This takes
// care of transforming headings of every level.
if (element.Name == W.p)
{
string styleId = (string)element.Elements(W.pPr).Elements(W.pStyle)
.Attributes(W.val).FirstOrDefault();
XElement style = wordDoc.MainDocumentPart.StyleDefinitionsPart
.GetXDocument().Root.Elements(W.style)
.Where(s => (string)s.Attribute(W.styleId) == styleId)
.FirstOrDefault();
if (style != null)
{
int? outlineLevel = (int?)style.Elements(W.pPr)
.Elements(W.outlineLvl).Attributes(W.val).FirstOrDefault();
if (outlineLevel != null)
{
return new XElement(Xhtml.xhtml + string.Format("h{0}",
outlineLevel + 1),
settings.CssClassPrefix != null ?
new XAttribute(HtmlNoNamespace._class,
settings.CssClassPrefix + styleId) : null,
ConvertEntities(ListItemRetriever.RetrieveListItem(wordDoc,
element, null)),
element.Elements().Select(e => ConvertToHtmlTransform(wordDoc,
settings, e, imageHandler)));
}
}
}
// Transform w:p to h:p.
if (element.Name == W.p)
{
string styleId = (string)element.Elements(W.pPr).Elements(W.pStyle)
.Attributes(W.val).FirstOrDefault();
if (styleId == null)
{
styleId = (string)wordDoc.MainDocumentPart.StyleDefinitionsPart
.GetXDocument().Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.type) == "paragraph" &&
(string)e.Attribute(W._default) == "1")
.FirstOrDefault().Attributes(W.styleId).FirstOrDefault();
}
XElement z = new XElement(Xhtml.p,
styleId != null ? (
settings.CssClassPrefix != null ?
new XAttribute(HtmlNoNamespace._class,
settings.CssClassPrefix + styleId) : null
) : null,
ConvertEntities(ListItemRetriever.RetrieveListItem(wordDoc,
element, null)),
element.Elements().Select(e => ConvertToHtmlTransform(wordDoc,
settings, e, imageHandler)));
return z;
}
// Transform every hyperlink in the document to the XHTML h:A element.
if (element.Name == W.hyperlink && element.Attribute(R.id) != null)
{
try
{
return new XElement(Xhtml.A,
new XAttribute(HtmlNoNamespace.href,
wordDoc.MainDocumentPart
.HyperlinkRelationships
.Where(x => x.Id == (string)element.Attribute(R.id))
.First()
.Uri
),
ConvertEntities(element.Elements(W.r)
.Elements(W.t)
.Select(s => (string)s).StringConcatenate())
);
}
catch (UriFormatException)
{
return element.Elements().Select(e => ConvertToHtmlTransform(wordDoc,
settings, e, imageHandler));
}
}
// Transform contents of runs that are part of a hyperlink.
if (element.Name == W.r &&
element.Annotation<FieldInfo>() != null &&
element.Annotation<FieldInfo>().Arguments.Length > 0)
{
FieldInfo fieldInfo = element.Annotation<FieldInfo>();
return new XElement(Xhtml.A,
new XAttribute(HtmlNoNamespace.href, fieldInfo.Arguments[0]),
ConvertEntities(element.Elements(W.t)
.Select(s => (string)s).StringConcatenate())
);
}
// Transform contents of runs.
if (element.Name == W.r)
return element.Elements().Select(e => ConvertToHtmlTransform(wordDoc,
settings, e, imageHandler));
// Transform every w:t element to a text node.
if (element.Name == W.t)
return ConvertEntities(element.Value);
// Transform w:br to h:br.
if (element.Name == W.br || element.Name == W.cr)
return new XElement(Xhtml.br);
// Transform w:noBreakHyphen to '-'
if (element.Name == W.noBreakHyphen)
return new XText("-");
// Transform w:tbl to h:tbl.
if (element.Name == W.tbl)
return new XElement(Xhtml.table,
new XAttribute(HtmlNoNamespace.border, 1),
element.Elements().Select(e => ConvertToHtmlTransform(wordDoc,
settings, e, imageHandler)));
// Transform w:tr to h:tr.
if (element.Name == W.tr)
return new XElement(Xhtml.tr,
element.Elements().Select(e => ConvertToHtmlTransform(wordDoc,
settings, e, imageHandler)));
// Transform w:tc to h:td.
if (element.Name == W.tc)
return new XElement(Xhtml.td,
element.Elements().Select(e => ConvertToHtmlTransform(wordDoc,
settings, e, imageHandler)));
// Transform images.
if (element.Name == W.drawing || element.Name == W.pict)
{
if (imageHandler == null)
return null;
return ProcessImage(wordDoc, element, imageHandler);
}
// The following removes any nodes that haven't been transformed.
return null;
}
return null;
}
private enum AnnotateState
{
NotInHyperlink,
InFirstSection,
InSecondSection,
}
private static void AnnotateHyperlinkContent(XElement rootElement)
{
AnnotateState state = AnnotateState.NotInHyperlink;
foreach (XElement blockLevelContentContainer in
rootElement.Descendants().Where(e => W.BlockLevelContentContainers.Contains(e.Name)))
{
FieldInfo fieldInfo = null;
foreach (XElement runLevelContent in blockLevelContentContainer
.LogicalChildrenContent(W.p).LogicalChildrenContent(W.r))
{
if (runLevelContent.Elements(W.fldChar).Attributes(W.fldCharType)
.Any(a => a.Value == "begin"))
state = AnnotateState.InFirstSection;
XElement instrText = runLevelContent.Elements(W.instrText).FirstOrDefault();
if (instrText != null && state == AnnotateState.InFirstSection)
{
FieldInfo tempFieldInfo = FieldParser.ParseField(instrText.Value);
if (tempFieldInfo.FieldType == "HYPERLINK")
fieldInfo = tempFieldInfo;
}
var z = runLevelContent.Elements(W.fldChar).FirstOrDefault();
if (runLevelContent.Elements(W.fldChar).Attributes(W.fldCharType)
.Any(a => a.Value == "separate"))
state = AnnotateState.InSecondSection;
if (runLevelContent.Elements(W.fldChar).Attributes(W.fldCharType)
.Any(a => a.Value == "end"))
{
fieldInfo = null;
state = AnnotateState.NotInHyperlink;
}
if (state == AnnotateState.InSecondSection && fieldInfo != null &&
(string)runLevelContent.Elements(W.rPr).Elements(W.rStyle)
.Attributes(W.val).FirstOrDefault() == "Hyperlink")
runLevelContent.AddAnnotation(fieldInfo);
}
}
}
private static void InitEntityMap()
{
EntityMap = new Dictionary<char, string>()
{
{ (char)160, "nbsp" },
{ (char)161, "iexcl" },
{ (char)162, "cent" },
{ (char)163, "pound" },
{ (char)164, "curren" },
{ (char)165, "yen" },
{ (char)166, "brvbar" },
{ (char)167, "sect" },
{ (char)168, "uml" },
{ (char)169, "copy" },
{ (char)170, "ordf" },
{ (char)171, "laquo" },
{ (char)172, "not" },
{ (char)173, "shy" },
{ (char)174, "reg" },
{ (char)175, "macr" },
{ (char)176, "deg" },
{ (char)177, "plusmn" },
{ (char)178, "sup2" },
{ (char)179, "sup3" },
{ (char)180, "acute" },
{ (char)181, "micro" },
{ (char)182, "para" },
{ (char)183, "middot" },
{ (char)184, "cedil" },
{ (char)185, "sup1" },
{ (char)186, "ordm" },
{ (char)187, "raquo" },
{ (char)188, "frac14" },
{ (char)189, "frac12" },
{ (char)190, "frac34" },
{ (char)191, "iquest" },
{ (char)192, "Agrave" },
{ (char)193, "Aacute" },
{ (char)194, "Acirc" },
{ (char)195, "Atilde" },
{ (char)196, "Auml" },
{ (char)197, "Aring" },
{ (char)198, "AElig" },
{ (char)199, "Ccedil" },
{ (char)200, "Egrave" },
{ (char)201, "Eacute" },
{ (char)202, "Ecirc" },
{ (char)203, "Euml" },
{ (char)204, "Igrave" },
{ (char)205, "Iacute" },
{ (char)206, "Icirc" },
{ (char)207, "Iuml" },
{ (char)208, "ETH" },
{ (char)209, "Ntilde" },
{ (char)210, "Ograve" },
{ (char)211, "Oacute" },
{ (char)212, "Ocirc" },
{ (char)213, "Otilde" },
{ (char)214, "Ouml" },
{ (char)215, "times" },
{ (char)216, "Oslash" },
{ (char)217, "Ugrave" },
{ (char)218, "Uacute" },
{ (char)219, "Ucirc" },
{ (char)220, "Uuml" },
{ (char)221, "Yacute" },
{ (char)222, "THORN" },
{ (char)223, "szlig" },
{ (char)224, "agrave" },
{ (char)225, "aacute" },
{ (char)226, "acirc" },
{ (char)227, "atilde" },
{ (char)228, "auml" },
{ (char)229, "aring" },
{ (char)230, "aelig" },
{ (char)231, "ccedil" },
{ (char)232, "egrave" },
{ (char)233, "eacute" },
{ (char)234, "ecirc" },
{ (char)235, "euml" },
{ (char)236, "igrave" },
{ (char)237, "iacute" },
{ (char)238, "icirc" },
{ (char)239, "iuml" },
{ (char)240, "eth" },
{ (char)241, "ntilde" },
{ (char)242, "ograve" },
{ (char)243, "oacute" },
{ (char)244, "ocirc" },
{ (char)245, "otilde" },
{ (char)246, "ouml" },
{ (char)247, "divide" },
{ (char)248, "oslash" },
{ (char)249, "ugrave" },
{ (char)250, "uacute" },
{ (char)251, "ucirc" },
{ (char)252, "uuml" },
{ (char)253, "yacute" },
{ (char)254, "thorn" },
{ (char)255, "yuml" },
{ (char)338, "OElig" },
{ (char)339, "oelig" },
{ (char)352, "Scaron" },
{ (char)353, "scaron" },
{ (char)376, "Yuml" },
{ (char)402, "fnof" },
{ (char)710, "circ" },
{ (char)732, "tilde" },
{ (char)913, "Alpha" },
{ (char)914, "Beta" },
{ (char)915, "Gamma" },
{ (char)916, "Delta" },
{ (char)917, "Epsilon" },
{ (char)918, "Zeta" },
{ (char)919, "Eta" },
{ (char)920, "Theta" },
{ (char)921, "Iota" },
{ (char)922, "Kappa" },
{ (char)923, "Lambda" },
{ (char)924, "Mu" },
{ (char)925, "Nu" },
{ (char)926, "Xi" },
{ (char)927, "Omicron" },
{ (char)928, "Pi" },
{ (char)929, "Rho" },
{ (char)931, "Sigma" },
{ (char)932, "Tau" },
{ (char)933, "Upsilon" },
{ (char)934, "Phi" },
{ (char)935, "Chi" },
{ (char)936, "Psi" },
{ (char)937, "Omega" },
{ (char)945, "alpha" },
{ (char)946, "beta" },
{ (char)947, "gamma" },
{ (char)948, "delta" },
{ (char)949, "epsilon" },
{ (char)950, "zeta" },
{ (char)951, "eta" },
{ (char)952, "theta" },
{ (char)953, "iota" },
{ (char)954, "kappa" },
{ (char)955, "lambda" },
{ (char)956, "mu" },
{ (char)957, "nu" },
{ (char)958, "xi" },
{ (char)959, "omicron" },
{ (char)960, "pi" },
{ (char)961, "rho" },
{ (char)962, "sigmaf" },
{ (char)963, "sigma" },
{ (char)964, "tau" },
{ (char)965, "upsilon" },
{ (char)966, "phi" },
{ (char)967, "chi" },
{ (char)968, "psi" },
{ (char)969, "omega" },
{ (char)977, "thetasym" },
{ (char)978, "upsih" },
{ (char)982, "piv" },
{ (char)8194, "ensp" },
{ (char)8195, "emsp" },
{ (char)8201, "thinsp" },
{ (char)8204, "zwnj" },
{ (char)8205, "zwj" },
{ (char)8206, "lrm" },
{ (char)8207, "rlm" },
{ (char)8211, "ndash" },
{ (char)8212, "mdash" },
{ (char)8216, "lsquo" },
{ (char)8217, "rsquo" },
{ (char)8218, "sbquo" },
{ (char)8220, "ldquo" },
{ (char)8221, "rdquo" },
{ (char)8222, "bdquo" },
{ (char)8224, "dagger" },
{ (char)8225, "Dagger" },
{ (char)8226, "bull" },
{ (char)8230, "hellip" },
{ (char)8240, "permil" },
{ (char)8242, "prime" },
{ (char)8243, "Prime" },
{ (char)8249, "lsaquo" },
{ (char)8250, "rsaquo" },
{ (char)8254, "oline" },
{ (char)8260, "frasl" },
{ (char)8364, "euro" },
{ (char)8465, "image" },
{ (char)8472, "weierp" },
{ (char)8476, "real" },
{ (char)8482, "trade" },
{ (char)8501, "alefsym" },
{ (char)8592, "larr" },
{ (char)8593, "uarr" },
{ (char)8594, "rarr" },
{ (char)8595, "darr" },
{ (char)8596, "harr" },
{ (char)8629, "crarr" },
{ (char)8656, "lArr" },
{ (char)8657, "uArr" },
{ (char)8658, "rArr" },
{ (char)8659, "dArr" },
{ (char)8660, "hArr" },
{ (char)8704, "forall" },
{ (char)8706, "part" },
{ (char)8707, "exist" },
{ (char)8709, "empty" },
{ (char)8711, "nabla" },
{ (char)8712, "isin" },
{ (char)8713, "notin" },
{ (char)8715, "ni" },
{ (char)8719, "prod" },
{ (char)8721, "sum" },
{ (char)8722, "minus" },
{ (char)8727, "lowast" },
{ (char)8730, "radic" },
{ (char)8733, "prop" },
{ (char)8734, "infin" },
{ (char)8736, "ang" },
{ (char)8743, "and" },
{ (char)8744, "or" },
{ (char)8745, "cap" },
{ (char)8746, "cup" },
{ (char)8747, "int" },
{ (char)8756, "there4" },
{ (char)8764, "sim" },
{ (char)8773, "cong" },
{ (char)8776, "asymp" },
{ (char)8800, "ne" },
{ (char)8801, "equiv" },
{ (char)8804, "le" },
{ (char)8805, "ge" },
{ (char)8834, "sub" },
{ (char)8835, "sup" },
{ (char)8836, "nsub" },
{ (char)8838, "sube" },
{ (char)8839, "supe" },
{ (char)8853, "oplus" },
{ (char)8855, "otimes" },
{ (char)8869, "perp" },
{ (char)8901, "sdot" },
{ (char)8968, "lceil" },
{ (char)8969, "rceil" },
{ (char)8970, "lfloor" },
{ (char)8971, "rfloor" },
{ (char)9001, "lang" },
{ (char)9002, "rang" },
{ (char)9674, "loz" },
{ (char)9824, "spades" },
{ (char)9827, "clubs" },
{ (char)9829, "hearts" },
{ (char)9830, "diams" },
};
}
public static XElement ConvertToHtml(WordprocessingDocument wordDoc,
HtmlConverterSettings htmlConverterSettings)
{
return ConvertToHtml(wordDoc, htmlConverterSettings, null);
}
public static XElement ConvertToHtml(WmlDocument doc, HtmlConverterSettings htmlConverterSettings)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
return ConvertToHtml(document, htmlConverterSettings);
}
}
}
public static XElement ConvertToHtml(WmlDocument doc, HtmlConverterSettings htmlConverterSettings, Func<ImageInfo, XElement> imageHandler)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
return ConvertToHtml(document, htmlConverterSettings, imageHandler);
}
}
}
public static XElement ConvertToHtml(WordprocessingDocument wordDoc,
HtmlConverterSettings htmlConverterSettings, Func<ImageInfo, XElement> imageHandler)
{
InitEntityMap();
if (htmlConverterSettings.ConvertFormatting)
{
throw new InvalidSettingsException("Conversion with formatting is not supported");
}
RevisionAccepter.AcceptRevisions(wordDoc);
SimplifyMarkupSettings settings = new SimplifyMarkupSettings
{
RemoveComments = true,
RemoveContentControls = true,
RemoveEndAndFootNotes = true,
RemoveFieldCodes = false,
RemoveLastRenderedPageBreak = true,
RemovePermissions = true,
RemoveProof = true,
RemoveRsidInfo = true,
RemoveSmartTags = true,
RemoveSoftHyphens = true,
ReplaceTabsWithSpaces = true,
};
MarkupSimplifier.SimplifyMarkup(wordDoc, settings);
XElement rootElement = wordDoc.MainDocumentPart.GetXDocument().Root;
AnnotateHyperlinkContent(rootElement);
XElement xhtml = (XElement)ConvertToHtmlTransform(wordDoc, htmlConverterSettings,
rootElement, imageHandler);
// Note: the xhtml returned by ConvertToHtmlTransform contains objects of type
// XEntity. PtOpenXmlUtil.cs define the XEntity class. See
// http://blogs.msdn.com/ericwhite/archive/2010/01/21/writing-entity-references-using-linq-to-xml.aspx
// for detailed explanation.
//
// If you further transform the XML tree returned by ConvertToHtmlTransform, you
// must do it correctly, or entities will not be serialized properly.
return xhtml;
}
}
}

View File

@@ -0,0 +1,104 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
/// <summary>
/// process available index references
/// </summary>
public class IndexAccessor
{
private static XNamespace ns;
static IndexAccessor()
{
ns = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
}
public static void Generate(WordprocessingDocument document)
{
XElement Index = new XElement("Index");
XElement IndexFirstPart =
new XElement(ns + "p",
new XElement(ns + "r",
new XElement(ns + "fldChar",
new XAttribute(ns + "fldCharType", "begin")),
new XElement(ns + "instrText",
new XAttribute(XNamespace.Xml + "space", "preserve"),
@" INDEX \h ""A"" \c ""2"" \z ""1033"" "),
new XElement(ns + "fldChar",
new XAttribute(ns + "fldCharType", "separate"))));
Index.Add(IndexFirstPart);
// Build the index with the IndexReferences
foreach (XElement reference in IndexReferences(document))
{
//string fieldCode = GetFieldCode(reference);
string mainEntry = reference.Value;//GetIndexMainEntry(reference.Value);
// Build the XElement containing the index reference
XElement IndexElement =
new XElement(ns + "p",
new XElement(ns + "pPr",
new XElement(ns + "pStyle",
new XAttribute(ns + "val", "Index1")),
new XElement(ns + "tabs",
new XElement(ns + "tab",
new XAttribute(ns + "val", "right"),
new XAttribute(ns + "leader", "dot"),
new XAttribute(ns + "pos", "9350")))),
new XElement(ns + "r",
new XElement(ns + "t", mainEntry)));
Index.Add(IndexElement);
}
// Close the open character field
Index.Add(
new XElement(ns + "p",
new XElement(ns + "r",
new XElement(ns + "fldChar",
new XAttribute(ns + "fldCharType", "end")))));
XDocument mainDocumentPart = document.MainDocumentPart.GetXDocument();
foreach (XElement IndexElement in Index.Elements())
{
mainDocumentPart.Descendants(ns + "body").First().Add(IndexElement);
}
document.MainDocumentPart.PutXDocument();
}
private static IEnumerable<XElement> IndexReferences(WordprocessingDocument document)
{
XDocument mainDocument = document.MainDocumentPart.GetXDocument();
IEnumerable<XElement> results =
mainDocument
.Descendants(ns + "p")
.Elements(ns + "r")
.Where(
r =>
r.Elements(ns + "instrText").Count() > 0 &&
r.ElementsBeforeSelf().Last().Element(ns + "instrText")!= null &&
r.ElementsBeforeSelf().Last().Element(ns + "instrText").Value.EndsWith("\"") &&
r.ElementsAfterSelf().First().Element(ns + "instrText") != null &&
r.ElementsAfterSelf().First().Element(ns + "instrText").Value.StartsWith("\"")
);
return results;
}
}
}

View File

@@ -0,0 +1,633 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2010.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license
can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
public partial class WmlDocument : OpenXmlPowerToolsDocument
{
public string RetrieveListItem(XElement paragraph, string bulletReplacementString)
{
return ListItemRetriever.RetrieveListItem(this, paragraph, bulletReplacementString);
}
}
public class ListItemRetriever
{
private class ListItemInfo
{
public bool IsListItem;
public XElement Lvl;
public int? Start;
public int? AbstractNumId;
public ListItemInfo(bool isListItem)
{
IsListItem = isListItem;
}
}
private class LevelNumbers
{
public int[] LevelNumbersArray;
}
private static ListItemInfo GetListItemInfoByNumIdAndIlvl(XDocument numbering,
XDocument styles, int numId, int ilvl)
{
if (numId == 0)
return new ListItemInfo(false);
ListItemInfo listItemInfo = new ListItemInfo(true);
XElement num = numbering.Root.Elements(W.num)
.Where(e => (int)e.Attribute(W.numId) == numId).FirstOrDefault();
if (num == null)
return new ListItemInfo(false);
listItemInfo.AbstractNumId = (int?)num.Elements(W.abstractNumId)
.Attributes(W.val).FirstOrDefault();
XElement lvlOverride = num.Elements(W.lvlOverride)
.Where(e => (int)e.Attribute(W.ilvl) == ilvl).FirstOrDefault();
// If there is a w:lvlOverride element, and if the w:lvlOverride contains a
// w:lvl element, then return it. Otherwise, go look in the abstract numbering
// definition.
if (lvlOverride != null)
{
// Get the startOverride, if there is one.
listItemInfo.Start = (int?)num.Elements(W.lvlOverride)
.Where(o => (int)o.Attribute(W.ilvl) == ilvl).Elements(W.startOverride)
.Attributes(W.val).FirstOrDefault();
listItemInfo.Lvl = lvlOverride.Element(W.lvl);
if (listItemInfo.Lvl != null)
{
if (listItemInfo.Start == null)
listItemInfo.Start = (int?)listItemInfo.Lvl.Elements(W.start)
.Attributes(W.val).FirstOrDefault();
return listItemInfo;
}
}
int? a = listItemInfo.AbstractNumId;
XElement abstractNum = numbering.Root.Elements(W.abstractNum)
.Where(e => (int)e.Attribute(W.abstractNumId) == a).FirstOrDefault();
string numStyleLink = (string)abstractNum.Elements(W.numStyleLink)
.Attributes(W.val).FirstOrDefault();
if (numStyleLink != null)
{
XElement style = styles.Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.styleId) == numStyleLink)
.FirstOrDefault();
XElement numPr = style.Elements(W.pPr).Elements(W.numPr).FirstOrDefault();
int lNumId = (int)numPr.Elements(W.numId).Attributes(W.val)
.FirstOrDefault();
return GetListItemInfoByNumIdAndIlvl(numbering, styles, lNumId, ilvl);
}
for (int l = ilvl; l >= 0; --l)
{
listItemInfo.Lvl = abstractNum.Elements(W.lvl)
.Where(e => (int)e.Attribute(W.ilvl) == l).FirstOrDefault();
if (listItemInfo.Lvl == null)
continue;
if (listItemInfo.Start == null)
listItemInfo.Start = (int?)listItemInfo.Lvl.Elements(W.start)
.Attributes(W.val).FirstOrDefault();
return listItemInfo;
}
return new ListItemInfo(false);
}
private static ListItemInfo GetListItemInfoByNumIdAndStyleId(XDocument numbering,
XDocument styles, int numId, string paragraphStyle)
{
// If you have to find the w:lvl by style id, then we can't find it in the
// w:lvlOverride, as that requires that you have determined the level already.
ListItemInfo listItemInfo = new ListItemInfo(true);
XElement num = numbering.Root.Elements(W.num)
.Where(e => (int)e.Attribute(W.numId) == numId).FirstOrDefault();
listItemInfo.AbstractNumId = (int)num.Elements(W.abstractNumId)
.Attributes(W.val).FirstOrDefault();
int? a = listItemInfo.AbstractNumId;
XElement abstractNum = numbering.Root.Elements(W.abstractNum)
.Where(e => (int)e.Attribute(W.abstractNumId) == a).FirstOrDefault();
string numStyleLink = (string)abstractNum.Element(W.numStyleLink)
.Attributes(W.val).FirstOrDefault();
if (numStyleLink != null)
{
XElement style = styles.Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.styleId) == numStyleLink)
.FirstOrDefault();
XElement numPr = style.Elements(W.pPr).Elements(W.numPr).FirstOrDefault();
int lNumId = (int)numPr.Elements(W.numId).Attributes(W.val).FirstOrDefault();
return GetListItemInfoByNumIdAndStyleId(numbering, styles, lNumId,
paragraphStyle);
}
listItemInfo.Lvl = abstractNum.Elements(W.lvl)
.Where(e => (string)e.Element(W.pStyle) == paragraphStyle).FirstOrDefault();
listItemInfo.Start = (int?)listItemInfo.Lvl.Elements(W.start).Attributes(W.val)
.FirstOrDefault();
return listItemInfo;
}
private static ListItemInfo GetListItemInfo(XDocument numbering, XDocument styles,
XElement paragraph)
{
// The following is an optimization - only determine ListItemInfo once for a
// paragraph.
ListItemInfo listItemInfo = paragraph.Annotation<ListItemInfo>();
if (listItemInfo != null)
return listItemInfo;
XElement paragraphNumberingProperties = paragraph.Elements(W.pPr)
.Elements(W.numPr).FirstOrDefault();
string paragraphStyle = (string)paragraph.Elements(W.pPr).Elements(W.pStyle)
.Attributes(W.val).FirstOrDefault();
if (paragraphNumberingProperties != null &&
paragraphNumberingProperties.Element(W.numId) != null)
{
// Paragraph numbering properties must contain a numId.
int numId = (int)paragraphNumberingProperties.Elements(W.numId)
.Attributes(W.val).FirstOrDefault();
int? ilvl = (int?)paragraphNumberingProperties.Elements(W.ilvl)
.Attributes(W.val).FirstOrDefault();
if (ilvl != null)
{
listItemInfo = GetListItemInfoByNumIdAndIlvl(numbering, styles, numId,
(int)ilvl);
paragraph.AddAnnotation(listItemInfo);
return listItemInfo;
}
if (paragraphStyle != null)
{
listItemInfo = GetListItemInfoByNumIdAndStyleId(numbering, styles,
numId, paragraphStyle);
paragraph.AddAnnotation(listItemInfo);
return listItemInfo;
}
listItemInfo = new ListItemInfo(false);
paragraph.AddAnnotation(listItemInfo);
return listItemInfo;
}
if (paragraphStyle != null)
{
XElement style = styles.Root.Elements(W.style).Where(s =>
(string)s.Attribute(W.type) == "paragraph" &&
(string)s.Attribute(W.styleId) == paragraphStyle).FirstOrDefault();
if (style != null)
{
XElement styleNumberingProperties = style.Elements(W.pPr)
.Elements(W.numPr).FirstOrDefault();
if (styleNumberingProperties != null &&
styleNumberingProperties.Element(W.numId) != null)
{
int numId = (int)styleNumberingProperties.Elements(W.numId)
.Attributes(W.val).FirstOrDefault();
int? ilvl = (int?)styleNumberingProperties.Elements(W.ilvl)
.Attributes(W.val).FirstOrDefault();
if (ilvl == null)
ilvl = 0;
listItemInfo = GetListItemInfoByNumIdAndIlvl(numbering, styles,
numId, (int)ilvl);
paragraph.AddAnnotation(listItemInfo);
return listItemInfo;
}
}
}
listItemInfo = new ListItemInfo(false);
paragraph.AddAnnotation(listItemInfo);
return listItemInfo;
}
private static IEnumerable<LevelNumbers> ParagraphsToConsiderWhenCounting(
XDocument numbering, XDocument styles, XElement paragraph, int levelNumber)
{
ListItemInfo listItemInfo = GetListItemInfo(numbering, styles, paragraph);
int? lvlRestart = (int?)listItemInfo.Lvl.Elements(W.lvlRestart)
.Attributes(W.val).FirstOrDefault();
int paragraphLevel = (int)listItemInfo.Lvl.Attribute(W.ilvl);
IEnumerable<XElement> paragraphsBeforeSelf = paragraph
.ElementsBeforeSelfReverseDocumentOrder().Where(e => e.Name == W.p);
foreach (var p in paragraphsBeforeSelf)
{
ListItemInfo pListItemInfo = GetListItemInfo(numbering, styles, p);
if (!pListItemInfo.IsListItem ||
pListItemInfo.AbstractNumId != listItemInfo.AbstractNumId)
continue;
LevelNumbers pLevelNumbers = p.Annotation<LevelNumbers>();
int pLevel = (int)pListItemInfo.Lvl.Attribute(W.ilvl);
if (pLevel > levelNumber)
yield return pLevelNumbers;
if (lvlRestart == null)
{
if (pLevel < levelNumber)
yield break;
}
else
{
if (pLevel < levelNumber && pLevel > lvlRestart - 1)
continue;
else if (pLevel < levelNumber)
yield break;
}
yield return pLevelNumbers;
}
}
private static int GetLevelNumberForLevel(XDocument numbering, XDocument styles,
XElement paragraph, int level)
{
ListItemInfo listItemInfo = GetListItemInfo(numbering, styles, paragraph);
int paragraphLevel = (int)listItemInfo.Lvl.Attribute(W.ilvl);
var paragraphsToConsider = ParagraphsToConsiderWhenCounting(numbering, styles,
paragraph, level)
.Select(o => o.LevelNumbersArray.Take(paragraphLevel + 1)
.Select(z => z.ToString() + ".").StringConcatenate())
.GroupBy(o => o);
int levelNumberForLevel = paragraphsToConsider.Count();
return levelNumberForLevel;
}
private static int[] GetLevelNumbers(XDocument numbering, XDocument styles,
XElement paragraph)
{
IEnumerable<XElement> paragraphsBeforeSelf = paragraph
.ElementsBeforeSelfReverseDocumentOrder().Where(e => e.Name == W.p);
int level;
ListItemInfo listItemInfo = GetListItemInfo(numbering, styles, paragraph);
level = (int)listItemInfo.Lvl.Attribute(W.ilvl);
List<int> levelNumbers = new List<int>();
for (int indentationLevel = 0; indentationLevel <= level; ++indentationLevel)
{
XElement currentIndentLvl = GetRelatedLevel(listItemInfo.Lvl,
indentationLevel);
int? start = (int?)currentIndentLvl.Elements(W.start).Attributes(W.val)
.FirstOrDefault();
if (start == null)
start = 1;
XElement paragraphWithSameAbstractNumId = paragraphsBeforeSelf
.FirstOrDefault(p =>
{
ListItemInfo pListItemInfo = GetListItemInfo(numbering, styles, p);
return pListItemInfo.IsListItem &&
pListItemInfo.AbstractNumId == listItemInfo.AbstractNumId;
});
if (paragraphWithSameAbstractNumId != null)
{
LevelNumbers pLevelNumbers = paragraphWithSameAbstractNumId
.Annotation<LevelNumbers>();
if (pLevelNumbers.LevelNumbersArray.Length > indentationLevel)
{
if (indentationLevel == level)
levelNumbers.Add(
pLevelNumbers.LevelNumbersArray[indentationLevel] + 1);
else
levelNumbers.Add(pLevelNumbers
.LevelNumbersArray[indentationLevel]);
continue;
}
}
if (level == indentationLevel)
{
int c1 = GetLevelNumberForLevel(numbering, styles, paragraph,
indentationLevel);
int? start2 = listItemInfo.Start;
if (start2 == null)
start2 = 1;
levelNumbers.Add(c1 + (int)start2);
continue;
}
levelNumbers.Add((int)start);
}
return levelNumbers.ToArray();
}
private static IEnumerable<string> GetFormatTokens(string lvlText)
{
int i = 0;
while (true)
{
if (i >= lvlText.Length)
yield break;
if (lvlText[i] == '%' && i <= lvlText.Length - 2)
{
yield return lvlText.Substring(i, 2);
i += 2;
continue;
}
int percentIndex = lvlText.IndexOf('%', i);
if (percentIndex == -1 || percentIndex > lvlText.Length - 2)
{
yield return lvlText.Substring(i);
yield break;
}
yield return lvlText.Substring(i, percentIndex - i);
yield return lvlText.Substring(percentIndex, 2);
i = percentIndex + 2;
}
}
private static string[] RomanOnes =
{
"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"
};
private static string[] RomanTens =
{
"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"
};
private static string[] RomanHundreds =
{
"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", "M"
};
private static string[] RomanThousands =
{
"", "M", "MM", "MMM", "MMMM", "MMMMM", "MMMMMM", "MMMMMMM", "MMMMMMMM",
"MMMMMMMMM", "MMMMMMMMMM"
};
private static string[] OneThroughNineteen = {
"one", "two", "three", "four", "five", "six", "seven", "eight",
"nine", "ten", "eleven", "twelve", "thirteen", "fourteen",
"fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
};
private static string[] Tens = {
"ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy",
"eighty", "ninety"
};
private static string[] OrdinalOneThroughNineteen = {
"first", "second", "third", "fourth", "fifth", "sixth",
"seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth",
"thirteenth", "fourteenth", "fifteenth", "sixteenth",
"seventeenth", "eighteenth", "nineteenth"
};
private static string[] OrdinalTenths = {
"tenth", "twentieth", "thirtieth", "fortieth", "fiftieth",
"sixtieth", "seventieth", "eightieth", "ninetieth"
};
private static string GetLevelText(int levelNumber, string numFmt)
{
if (numFmt == "decimal")
{
return levelNumber.ToString();
}
if (numFmt == "decimalZero")
{
if (levelNumber <= 9)
return "0" + levelNumber.ToString();
else
return levelNumber.ToString();
}
if (numFmt == "upperRoman")
{
int ones = levelNumber % 10;
int tens = (levelNumber % 100) / 10;
int hundreds = (levelNumber % 1000) / 100;
int thousands = levelNumber / 1000;
return RomanThousands[thousands] + RomanHundreds[hundreds] +
RomanTens[tens] + RomanOnes[ones];
}
if (numFmt == "lowerRoman")
{
int ones = levelNumber % 10;
int tens = (levelNumber % 100) / 10;
int hundreds = (levelNumber % 1000) / 100;
int thousands = levelNumber / 1000;
return (RomanThousands[thousands] + RomanHundreds[hundreds] +
RomanTens[tens] + RomanOnes[ones]).ToLower();
}
if (numFmt == "upperLetter")
{
string a = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int c = (levelNumber - 1) / 26;
int n = (levelNumber - 1) % 26;
char x = a[n];
return "".PadRight(c + 1, x);
}
if (numFmt == "lowerLetter")
{
string a = "abcdefghijklmnopqrstuvwxyz";
int c = (levelNumber - 1) / 26;
int n = (levelNumber - 1) % 26;
char x = a[n];
return "".PadRight(c + 1, x);
}
if (numFmt == "ordinal")
{
string suffix;
if (levelNumber % 100 == 11 || levelNumber % 100 == 12 ||
levelNumber % 100 == 13)
suffix = "th";
else if (levelNumber % 10 == 1)
suffix = "st";
else if (levelNumber % 10 == 2)
suffix = "nd";
else if (levelNumber % 10 == 3)
suffix = "rd";
else
suffix = "th";
return levelNumber.ToString() + suffix;
}
if (numFmt == "cardinalText")
{
string result = "";
int t1 = levelNumber / 1000;
int t2 = levelNumber % 1000;
if (t1 >= 1)
result += OneThroughNineteen[t1 - 1] + " thousand";
if (t1 >= 1 && t2 == 0)
return result.Substring(0, 1).ToUpper() +
result.Substring(1);
if (t1 >= 1)
result += " ";
int h1 = (levelNumber % 1000) / 100;
int h2 = levelNumber % 100;
if (h1 >= 1)
result += OneThroughNineteen[h1 - 1] + " hundred";
if (h1 >= 1 && h2 == 0)
return result.Substring(0, 1).ToUpper() +
result.Substring(1);
if (h1 >= 1)
result += " ";
int z = levelNumber % 100;
if (z <= 19)
result += OneThroughNineteen[z - 1];
else
{
int x = z / 10;
int r = z % 10;
result += Tens[x - 1];
if (r >= 1)
result += "-" + OneThroughNineteen[r - 1];
}
return result.Substring(0, 1).ToUpper() +
result.Substring(1);
}
if (numFmt == "ordinalText")
{
string result = "";
int t1 = levelNumber / 1000;
int t2 = levelNumber % 1000;
if (t1 >= 1 && t2 != 0)
result += OneThroughNineteen[t1 - 1] + " thousand";
if (t1 >= 1 && t2 == 0)
{
result += OneThroughNineteen[t1 - 1] + " thousandth";
return result.Substring(0, 1).ToUpper() +
result.Substring(1);
}
if (t1 >= 1)
result += " ";
int h1 = (levelNumber % 1000) / 100;
int h2 = levelNumber % 100;
if (h1 >= 1 && h2 != 0)
result += OneThroughNineteen[h1 - 1] + " hundred";
if (h1 >= 1 && h2 == 0)
{
result += OneThroughNineteen[h1 - 1] + " hundredth";
return result.Substring(0, 1).ToUpper() +
result.Substring(1);
}
if (h1 >= 1)
result += " ";
int z = levelNumber % 100;
if (z <= 19)
result += OrdinalOneThroughNineteen[z - 1];
else
{
int x = z / 10;
int r = z % 10;
if (r == 0)
result += OrdinalTenths[x - 1];
else
result += Tens[x - 1];
if (r >= 1)
result += "-" + OrdinalOneThroughNineteen[r - 1];
}
return result.Substring(0, 1).ToUpper() +
result.Substring(1);
}
if (numFmt == "bullet")
return "";
// This method needs to be enhanced to support all languages and
// all number formats.
return levelNumber.ToString();
}
private static XElement GetRelatedLevel(XElement lvl, int level)
{
XElement parent = lvl.Parent;
XElement newLvl;
if (parent.Name == W.lvlOverride)
{
newLvl = parent.Parent.Elements(W.lvlOverride).Elements(W.lvl)
.Where(e => (int)e.Attribute(W.ilvl) == level).FirstOrDefault();
if (newLvl != null)
return newLvl;
int abstractNumId = (int)parent.Parent.Elements(W.abstractNumId)
.Attributes(W.val).FirstOrDefault();
XElement abstractNum = lvl.Ancestors().Last().Elements(W.abstractNum)
.Where(e => (int)e.Attribute(W.abstractNumId) == abstractNumId)
.FirstOrDefault();
newLvl = abstractNum.Elements(W.lvl)
.Where(e => (int)e.Attribute(W.ilvl) == level).FirstOrDefault();
return newLvl;
}
newLvl = parent.Elements(W.lvl).Where(e => (int)e.Attribute(W.ilvl) == level)
.FirstOrDefault();
return newLvl;
}
private static string FormatListItem(XElement lvl, int[] levelNumbers,
string lvlText, string bulletReplacementString)
{
if (bulletReplacementString != null)
{
StringBuilder sb = new StringBuilder(lvlText);
sb.Replace("\xF076", bulletReplacementString);
sb.Replace("\xF0D8", bulletReplacementString);
sb.Replace("\xF0A7", bulletReplacementString);
sb.Replace("\xF0B7", bulletReplacementString);
sb.Replace("\xF0A8", bulletReplacementString);
sb.Replace("\xF0FC", bulletReplacementString);
lvlText = sb.ToString();
}
string[] formatTokens = GetFormatTokens(lvlText).ToArray();
bool isLgl = lvl.Elements(W.isLgl).Any();
string listItem = formatTokens.Select((t, l) =>
{
if (t.Substring(0, 1) != "%")
return t;
int indentationLevel = Int32.Parse(t.Substring(1)) - 1;
int levelNumber = levelNumbers[indentationLevel];
string levelText;
XElement rlvl = GetRelatedLevel(lvl, indentationLevel);
string numFmtForLevel = (string)rlvl.Elements(W.numFmt).Attributes(W.val)
.FirstOrDefault();
if (isLgl && numFmtForLevel != "decimalZero")
numFmtForLevel = "decimal";
levelText = GetLevelText(levelNumber, numFmtForLevel);
return levelText;
}).StringConcatenate();
return listItem + " ";
}
public static string RetrieveListItem(WmlDocument document,
XElement paragraph, string bulletReplacementString)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(document))
{
using (WordprocessingDocument wdoc = streamDoc.GetWordprocessingDocument())
{
return RetrieveListItem(wdoc, paragraph, bulletReplacementString);
}
}
}
public static string RetrieveListItem(WordprocessingDocument wordDoc,
XElement paragraph, string bulletReplacementString)
{
string pt = paragraph.Elements(W.r).Elements(W.t).Select(e => e.Value)
.StringConcatenate();
NumberingDefinitionsPart numberingDefinitionsPart =
wordDoc.MainDocumentPart.NumberingDefinitionsPart;
if (numberingDefinitionsPart == null)
return null;
StyleDefinitionsPart styleDefinitionsPart = wordDoc.MainDocumentPart
.StyleDefinitionsPart;
if (styleDefinitionsPart == null)
return null;
XDocument numbering = numberingDefinitionsPart.GetXDocument();
XDocument styles = styleDefinitionsPart.GetXDocument();
ListItemInfo listItemInfo = GetListItemInfo(numbering, styles, paragraph);
if (listItemInfo.IsListItem)
{
string lvlText = (string)listItemInfo.Lvl.Elements(W.lvlText)
.Attributes(W.val).FirstOrDefault();
int[] levelNumbers = GetLevelNumbers(numbering, styles, paragraph);
paragraph.AddAnnotation(new LevelNumbers()
{
LevelNumbersArray = levelNumbers
});
string listItem = FormatListItem(listItemInfo.Lvl, levelNumbers, lvlText,
bulletReplacementString);
return listItem;
}
return null;
}
}
}

View File

@@ -0,0 +1,688 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license
can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Schema;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
public partial class WmlDocument : OpenXmlPowerToolsDocument
{
public WmlDocument SimplifyMarkup(SimplifyMarkupSettings settings)
{
return MarkupSimplifier.SimplifyMarkup(this, settings);
}
}
public class SimplifyMarkupSettings
{
public bool AcceptRevisions;
public bool RemoveContentControls;
public bool RemoveSmartTags;
public bool RemoveRsidInfo;
public bool RemoveComments;
public bool RemoveEndAndFootNotes;
public bool ReplaceTabsWithSpaces;
public bool RemoveFieldCodes;
public bool RemovePermissions;
public bool RemoveProof;
public bool RemoveSoftHyphens;
public bool RemoveLastRenderedPageBreak;
public bool RemoveBookmarks;
public bool RemoveWebHidden;
public bool RemoveGoBackBookmark;
public bool NormalizeXml;
}
public static class MarkupSimplifier
{
public static WmlDocument SimplifyMarkup(WmlDocument doc, SimplifyMarkupSettings settings)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
SimplifyMarkup(document, settings);
}
return streamDoc.GetModifiedWmlDocument();
}
}
public static void SimplifyMarkup(WordprocessingDocument doc,
SimplifyMarkupSettings settings)
{
if (settings.AcceptRevisions)
RevisionAccepter.AcceptRevisions(doc);
foreach (var part in doc.ContentParts())
SimplifyMarkupForPart(part, settings);
if (doc.MainDocumentPart.StyleDefinitionsPart != null)
SimplifyMarkupForPart(doc.MainDocumentPart.StyleDefinitionsPart, settings);
if (doc.MainDocumentPart.StylesWithEffectsPart != null)
SimplifyMarkupForPart(doc.MainDocumentPart.StylesWithEffectsPart, settings);
}
public static XElement MergeAdjacentSuperfluousRuns(XElement element)
{
return (XElement)MergeAdjacentRunsTransform(element);
}
public static XElement TransformElementToSingleCharacterRuns(XElement element)
{
return (XElement)SingleCharacterRunTransform(element);
}
public static void TransformPartToSingleCharacterRuns(OpenXmlPart part)
{
// After transforming to single character runs, Rsid info will be invalid, so
// remove from the part.
XDocument xDoc = part.GetXDocument();
XElement newRoot = (XElement)RemoveRsidTransform(xDoc.Root);
newRoot = (XElement)SingleCharacterRunTransform(newRoot);
xDoc.Elements().First().ReplaceWith(newRoot);
part.PutXDocument();
}
public static void TransformToSingleCharacterRuns(WordprocessingDocument doc)
{
if (RevisionAccepter.HasTrackedRevisions(doc))
throw new OpenXmlPowerToolsException(
"Transforming a document to single character runs is not supported for " +
"a document with tracked revisions.");
foreach (var part in doc.ContentParts())
TransformPartToSingleCharacterRuns(part);
}
private static object RemoveCustomXmlAndContentControlsTransform(
XNode node, SimplifyMarkupSettings simplifyMarkupSettings)
{
XElement element = node as XElement;
if (element != null)
{
if (simplifyMarkupSettings.RemoveSmartTags &&
element.Name == W.smartTag)
return element
.Elements()
.Select(e =>
RemoveCustomXmlAndContentControlsTransform(e,
simplifyMarkupSettings));
if (simplifyMarkupSettings.RemoveContentControls &&
element.Name == W.sdt)
return element
.Element(W.sdtContent)
.Elements()
.Select(e =>
RemoveCustomXmlAndContentControlsTransform(e,
simplifyMarkupSettings));
}
return node;
}
private static object RemoveRsidTransform(XNode node)
{
XElement element = node as XElement;
if (element != null)
{
if (element.Name == W.rsid)
return null;
return new XElement(element.Name,
element.Attributes().Where(a => a.Name != W.rsid &&
a.Name != W.rsidDel &&
a.Name != W.rsidP &&
a.Name != W.rsidR &&
a.Name != W.rsidRDefault &&
a.Name != W.rsidRPr &&
a.Name != W.rsidSect &&
a.Name != W.rsidTr),
element.Nodes().Select(n => RemoveRsidTransform(n)));
}
return node;
}
private static XAttribute GetXmlSpaceAttribute(
string textElementValue)
{
if (textElementValue.Length > 0 &&
(textElementValue[0] == ' ' ||
textElementValue[textElementValue.Length - 1] == ' '))
return new XAttribute(XNamespace.Xml + "space",
"preserve");
return null;
}
private static object MergeAdjacentRunsTransform(XNode node)
{
XElement element = node as XElement;
if (element != null)
{
if (element.Name == W.p)
{
XElement paragraph = element;
var runGroups = paragraph
.Elements()
.GroupAdjacent(r =>
{
if (r.Name != W.r)
return "NotRuns";
XElement rPr = r.Element(W.rPr);
if (rPr == null)
return "NoRunProperties";
return rPr.ToString(
SaveOptions.DisableFormatting);
});
XElement newParagraph = new XElement(W.p,
paragraph.Attributes(),
runGroups.Select(g =>
{
if (g.Key == "NotRuns")
return (object)g;
if (g.Key == "NoRunProperties")
{
XElement newRun = new XElement(W.r,
g.First().Attributes(),
g.Elements()
.GroupAdjacent(c => c.Name)
.Select(gc =>
{
if (gc.Key != W.t)
return (object)gc;
string textElementValue =
gc.Select(t => (string)t)
.StringConcatenate();
return new XElement(W.t,
GetXmlSpaceAttribute(
textElementValue),
textElementValue);
}));
return newRun;
}
XElement runPropertyElement = XElement.Parse(
g.Key);
runPropertyElement.Attributes()
.Where(a => a.IsNamespaceDeclaration)
.Remove();
XElement newRunWithProperties = new XElement(
W.r,
g.First().Attributes(),
runPropertyElement,
g.Elements()
.Where(e => e.Name != W.rPr)
.GroupAdjacent(c => c.Name)
.Select(gc =>
{
if (gc.Key != W.t)
return (object)gc;
string textElementValue = gc
.Select(t => (string)t)
.StringConcatenate();
return new XElement(W.t,
GetXmlSpaceAttribute(
textElementValue),
textElementValue);
}));
return newRunWithProperties;
}
));
return newParagraph;
}
return new XElement(element.Name,
element.Attributes(),
element.Nodes().Select(n =>
MergeAdjacentRunsTransform(n)));
}
return node;
}
private static object RemoveEmptyRunsAndRunPropertiesTransform(
XNode node)
{
XElement element = node as XElement;
if (element != null)
{
if ((element.Name == W.r || element.Name == W.rPr || element.Name == W.pPr) &&
!element.Elements().Any())
return null;
return new XElement(element.Name,
element.Attributes(),
element.Nodes()
.Select(n =>
RemoveEmptyRunsAndRunPropertiesTransform(n)));
}
return node;
}
private static object MergeAdjacentInstrText(
XNode node)
{
XElement element = node as XElement;
if (element != null)
{
if (element.Name == W.r && element.Elements(W.instrText).Any())
{
var grouped = element.Elements().GroupAdjacent(e => e.Name == W.instrText);
return new XElement(W.r,
grouped.Select(g =>
{
if (g.Key == false)
return (object)g;
string newInstrText = g.Select(i => (string)i).StringConcatenate();
return new XElement(W.instrText,
newInstrText[0] == ' ' || newInstrText[newInstrText.Length - 1] == ' ' ?
new XAttribute(XNamespace.Xml + "space", "preserve") : null,
newInstrText);
}));
}
return new XElement(element.Name,
element.Attributes(),
element.Nodes()
.Select(n =>
MergeAdjacentInstrText(n)));
}
return node;
}
// lastRenderedPageBreak, permEnd, permStart, proofErr, noProof
// softHyphen:
// Remove when simplifying.
// fldSimple, fldData, fldChar, instrText:
// For hyperlinks, generate same in XHtml. Other than hyperlinks, do the following:
// - collapse fldSimple
// - remove fldSimple, fldData, fldChar, instrText.
private static object SimplifyMarkupTransform(
XNode node,
SimplifyMarkupSettings settings,
SimplifyMarkupParameters parameters)
{
XElement element = node as XElement;
if (element != null)
{
if (settings.RemovePermissions &&
(element.Name == W.permEnd ||
element.Name == W.permStart))
return null;
if (settings.RemoveProof &&
(element.Name == W.proofErr ||
element.Name == W.noProof))
return null;
if (settings.RemoveSoftHyphens &&
element.Name == W.softHyphen)
return null;
if (settings.RemoveLastRenderedPageBreak &&
element.Name == W.lastRenderedPageBreak)
return null;
if (settings.RemoveBookmarks &&
(element.Name == W.bookmarkStart ||
element.Name == W.bookmarkEnd))
return null;
if (settings.RemoveGoBackBookmark &&
((element.Name == W.bookmarkStart && (int)element.Attribute(W.id) == parameters.GoBackId) ||
(element.Name == W.bookmarkEnd && (int)element.Attribute(W.id) == parameters.GoBackId)))
return null;
if (settings.RemoveWebHidden &&
element.Name == W.webHidden)
return null;
if (settings.ReplaceTabsWithSpaces && element.Name == W.tab &&
element.Parent.Name == W.r)
return new XElement(W.t,
new XAttribute(XNamespace.Xml + "space", "preserve"),
" ");
if (settings.RemoveComments &&
(element.Name == W.commentRangeStart ||
element.Name == W.commentRangeEnd ||
element.Name == W.commentReference ||
element.Name == W.annotationRef))
return null;
if (settings.RemoveComments &&
element.Name == W.rStyle &&
element.Attribute(W.val).Value == "CommentReference")
return null;
if (settings.RemoveEndAndFootNotes &&
(element.Name == W.endnoteReference ||
element.Name == W.footnoteReference))
return null;
if (settings.RemoveFieldCodes)
{
if (element.Name == W.fldSimple)
return element.Elements().Select(e =>
SimplifyMarkupTransform(e, settings, parameters));
if (element.Name == W.fldData ||
element.Name == W.fldChar ||
element.Name == W.instrText)
return null;
}
return new XElement(element.Name,
element.Attributes(),
element.Nodes().Select(n =>
SimplifyMarkupTransform(n, settings, parameters)));
}
return node;
}
private static class Xsi
{
public static XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
public static XName schemaLocation = xsi + "schemaLocation";
public static XName noNamespaceSchemaLocation = xsi + "noNamespaceSchemaLocation";
}
private static XDocument Normalize(XDocument source, XmlSchemaSet schema)
{
bool havePSVI = false;
// validate, throw errors, add PSVI information
if (schema != null)
{
source.Validate(schema, null, true);
havePSVI = true;
}
return new XDocument(
source.Declaration,
source.Nodes().Select(n =>
{
// Remove comments, processing instructions, and text nodes that are
// children of XDocument. Only white space text nodes are allowed as
// children of a document, so we can remove all text nodes.
if (n is XComment || n is XProcessingInstruction || n is XText)
return null;
XElement e = n as XElement;
if (e != null)
return NormalizeElement(e, havePSVI);
return n;
}
)
);
}
private static bool DeepEqualsWithNormalization(XDocument doc1, XDocument doc2,
XmlSchemaSet schemaSet)
{
XDocument d1 = Normalize(doc1, schemaSet);
XDocument d2 = Normalize(doc2, schemaSet);
return XNode.DeepEquals(d1, d2);
}
private static IEnumerable<XAttribute> NormalizeAttributes(XElement element,
bool havePSVI)
{
return element.Attributes()
.Where(a => !a.IsNamespaceDeclaration &&
a.Name != Xsi.schemaLocation &&
a.Name != Xsi.noNamespaceSchemaLocation)
.OrderBy(a => a.Name.NamespaceName)
.ThenBy(a => a.Name.LocalName)
.Select(
a =>
{
if (havePSVI)
{
var dt = a.GetSchemaInfo().SchemaType.TypeCode;
switch (dt)
{
case XmlTypeCode.Boolean:
return new XAttribute(a.Name, (bool)a);
case XmlTypeCode.DateTime:
return new XAttribute(a.Name, (DateTime)a);
case XmlTypeCode.Decimal:
return new XAttribute(a.Name, (decimal)a);
case XmlTypeCode.Double:
return new XAttribute(a.Name, (double)a);
case XmlTypeCode.Float:
return new XAttribute(a.Name, (float)a);
case XmlTypeCode.HexBinary:
case XmlTypeCode.Language:
return new XAttribute(a.Name,
((string)a).ToLower());
}
}
return a;
}
);
}
private static XNode NormalizeNode(XNode node, bool havePSVI)
{
// trim comments and processing instructions from normalized tree
if (node is XComment || node is XProcessingInstruction)
return null;
XElement e = node as XElement;
if (e != null)
return NormalizeElement(e, havePSVI);
// Only thing left is XCData and XText, so clone them
return node;
}
private static XElement NormalizeElement(XElement element, bool havePSVI)
{
if (havePSVI)
{
var dt = element.GetSchemaInfo();
switch (dt.SchemaType.TypeCode)
{
case XmlTypeCode.Boolean:
return new XElement(element.Name,
NormalizeAttributes(element, havePSVI),
(bool)element);
case XmlTypeCode.DateTime:
return new XElement(element.Name,
NormalizeAttributes(element, havePSVI),
(DateTime)element);
case XmlTypeCode.Decimal:
return new XElement(element.Name,
NormalizeAttributes(element, havePSVI),
(decimal)element);
case XmlTypeCode.Double:
return new XElement(element.Name,
NormalizeAttributes(element, havePSVI),
(double)element);
case XmlTypeCode.Float:
return new XElement(element.Name,
NormalizeAttributes(element, havePSVI),
(float)element);
case XmlTypeCode.HexBinary:
case XmlTypeCode.Language:
return new XElement(element.Name,
NormalizeAttributes(element, havePSVI),
((string)element).ToLower());
default:
return new XElement(element.Name,
NormalizeAttributes(element, havePSVI),
element.Nodes().Select(n => NormalizeNode(n, havePSVI))
);
}
}
else
{
return new XElement(element.Name,
NormalizeAttributes(element, havePSVI),
element.Nodes().Select(n => NormalizeNode(n, havePSVI))
);
}
}
private static void SimplifyMarkupForPart(
OpenXmlPart part,
SimplifyMarkupSettings settings)
{
SimplifyMarkupParameters parameters = new SimplifyMarkupParameters();
if (part.ContentType == "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml")
{
WordprocessingDocument doc = (WordprocessingDocument)part.OpenXmlPackage;
if (settings.RemoveGoBackBookmark == true)
{
var goBackBookmark = doc
.MainDocumentPart
.GetXDocument()
.Root
.Descendants(W.bookmarkStart)
.FirstOrDefault(bm => (string)bm.Attribute(W.name) == "_GoBack");
if (goBackBookmark != null)
parameters.GoBackId = (int)goBackBookmark.Attribute(W.id);
}
}
XDocument xdoc = part.GetXDocument();
XElement newRoot = xdoc.Root;
// Need to do this first to enable simplifying hyperlinks.
if (settings.RemoveContentControls ||
settings.RemoveSmartTags)
newRoot = (XElement)
RemoveCustomXmlAndContentControlsTransform(
newRoot, settings);
// This may touch many elements, so needs to be its own
// transform.
if (settings.RemoveRsidInfo)
newRoot = (XElement)RemoveRsidTransform(newRoot);
XDocument prevNewRoot = new XDocument(newRoot);
while (true)
{
if (settings.RemoveComments ||
settings.RemoveEndAndFootNotes ||
settings.ReplaceTabsWithSpaces ||
settings.RemoveFieldCodes ||
settings.RemovePermissions ||
settings.RemoveProof ||
settings.RemoveBookmarks ||
settings.RemoveWebHidden ||
settings.RemoveGoBackBookmark)
newRoot = (XElement)SimplifyMarkupTransform(newRoot,
settings, parameters);
// Remove runs and run properties that have become empty due to previous
// transforms.
newRoot = (XElement)
RemoveEmptyRunsAndRunPropertiesTransform(newRoot);
// Merge adjacent runs that have identical run properties.
newRoot = (XElement)MergeAdjacentRunsTransform(newRoot);
// Merge adjacent instrText elements.
newRoot = (XElement)MergeAdjacentInstrText(newRoot);
if (XNode.DeepEquals(prevNewRoot.Root, newRoot))
break;
prevNewRoot = new XDocument(newRoot);
}
if (settings.NormalizeXml)
{
XAttribute[] ns_attrs =
{
new XAttribute(XNamespace.Xmlns + "wpc", WPC.wpc),
new XAttribute(XNamespace.Xmlns + "mc", MC.mc),
new XAttribute(XNamespace.Xmlns + "o", O.o),
new XAttribute(XNamespace.Xmlns + "r", R.r),
new XAttribute(XNamespace.Xmlns + "m", M.m),
new XAttribute(XNamespace.Xmlns + "v", VML.vml),
new XAttribute(XNamespace.Xmlns + "wp14", WP14.wp14),
new XAttribute(XNamespace.Xmlns + "wp", WP.wp),
new XAttribute(XNamespace.Xmlns + "w10", W10.w10),
new XAttribute(XNamespace.Xmlns + "w", W.w),
new XAttribute(XNamespace.Xmlns + "w14", W14.w14),
new XAttribute(XNamespace.Xmlns + "wpg", WPG.wpg),
new XAttribute(XNamespace.Xmlns + "wpi", WPI.wpi),
new XAttribute(XNamespace.Xmlns + "wne", WNE.wne),
new XAttribute(XNamespace.Xmlns + "wps", WPS.wps),
new XAttribute(MC.Ignorable, "w14 wp14"),
};
XDocument newXDoc = Normalize(new XDocument(newRoot), null);
foreach (var nsatt in ns_attrs)
{
if (newXDoc.Root.Attribute(nsatt.Name) == null)
newXDoc.Root.Add(nsatt);
}
part.PutXDocument(newXDoc);
}
else
{
part.PutXDocument(new XDocument(newRoot));
}
}
private static object SingleCharacterRunTransform(XNode node)
{
XElement element = node as XElement;
if (element != null)
{
if (element.Name == W.r)
{
var replacementRuns = element.Elements()
.Where(e => e.Name != W.rPr)
.GroupAdjacent(sr => sr.Name == W.t)
.Select(g =>
{
if (g.Key)
{
string s = g.Select(t => (string)t).StringConcatenate();
var newTextRuns = s.Select(c =>
new XElement(W.r,
element.Elements(W.rPr),
new XElement(W.t,
c == ' ' ? new XAttribute(XNamespace.Xml + "space", "preserve") : null,
c)));
return newTextRuns;
}
var newNonTextRuns = g.Select(sr =>
new XElement(W.r,
element.Elements(W.rPr),
new XElement(sr.Name,
sr.Attributes(),
sr.Nodes().Select(n => SingleCharacterRunTransform(n)))));
return newNonTextRuns;
});
return replacementRuns;
}
return new XElement(element.Name,
element.Attributes(),
element.Nodes().Select(n => SingleCharacterRunTransform(n)));
}
return node;
}
public class InternalException : Exception
{
public InternalException(string message) : base(message) { }
}
public class InvalidSettingsException : Exception
{
public InvalidSettingsException(string message) : base(message) { }
}
private class SimplifyMarkupParameters
{
public int? GoBackId { get; set; }
}
}
}

View File

@@ -0,0 +1,164 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using DocumentFormat.OpenXml.Packaging;
using System;
using System.Drawing.Imaging;
namespace OpenXmlPowerTools
{
/// <summary>
/// Provides access to picture operations
/// </summary>
public class PictureAccessor
{
private static XNamespace mainns;
private static XNamespace wordprocessingDrawingns;
private static XNamespace drawingmlMainns;
private static XNamespace picturens;
private static XNamespace relationshipns;
private const int pixelsPerEmu = 9525;
static PictureAccessor() {
mainns = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
wordprocessingDrawingns = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
drawingmlMainns = "http://schemas.openxmlformats.org/drawingml/2006/main";
picturens = "http://schemas.openxmlformats.org/drawingml/2006/picture";
relationshipns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
}
public static OpenXmlPowerToolsDocument Insert(WmlDocument doc, string xpathInsertionPoint, Image pictureToInsert, string name)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
XDocument xmlMainDocument = document.MainDocumentPart.GetXDocument();
ImagePart picturePart = null;
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(new NameTable());
namespaceManager.AddNamespace("w", mainns.NamespaceName);
IEnumerable<XElement> insertionPoints = xmlMainDocument.XPathSelectElements(xpathInsertionPoint, namespaceManager);
//make the insertion for each insertion point specified in the xpath query
foreach (XElement insertionPoint in insertionPoints)
{
if (picturePart == null)
{
// Create the picture part in the package
picturePart = document.MainDocumentPart.AddImagePart(GetImagePartType(pictureToInsert.RawFormat));
}
// the pictures in the main document part goes in a very long xml, wich specifies the way the picture
// has to be placed using drawingXml.
insertionPoint.AddAfterSelf(
new XElement(mainns + "p",
new XElement(mainns + "r",
new XElement(mainns + "drawing",
new XElement(wordprocessingDrawingns + "inline",
new XElement(wordprocessingDrawingns + "extent",
new XAttribute("cx", pictureToInsert.Width * pixelsPerEmu),
new XAttribute("cy", pictureToInsert.Height * pixelsPerEmu)
),
new XElement(wordprocessingDrawingns + "docPr",
new XAttribute("name", name),
new XAttribute("id", "1")
),
new XElement(drawingmlMainns + "graphic",
new XAttribute(XNamespace.Xmlns + "a", drawingmlMainns.NamespaceName),
new XElement(drawingmlMainns + "graphicData",
new XAttribute("uri", picturens.NamespaceName),
new XElement(picturens + "pic",
new XAttribute(XNamespace.Xmlns + "pic", picturens.NamespaceName),
new XElement(picturens + "nvPicPr",
new XElement(picturens + "cNvPr",
new XAttribute("id", "0"),
new XAttribute("name", name)
),
new XElement(picturens + "cNvPicPr")
),
new XElement(picturens + "blipFill",
new XElement(drawingmlMainns + "blip",
new XAttribute(relationshipns + "embed", document.MainDocumentPart.GetIdOfPart(picturePart))
),
new XElement(drawingmlMainns + "stretch",
new XElement(drawingmlMainns + "fillRect")
)
),
new XElement(picturens + "spPr",
new XElement(drawingmlMainns + "xfrm",
new XElement(drawingmlMainns + "off",
new XAttribute("x", "0"),
new XAttribute("y", "0")
),
new XElement(drawingmlMainns + "ext",
new XAttribute("cx", pictureToInsert.Width * pixelsPerEmu),
new XAttribute("cy", pictureToInsert.Height * pixelsPerEmu)
)
),
new XElement(drawingmlMainns + "prstGeom",
new XAttribute("prst", "rect")
)
)
)
)
)
)
)
)
)
);
}
if (picturePart != null)
{
Stream partStream = picturePart.GetStream(FileMode.Create, FileAccess.ReadWrite);
pictureToInsert.Save(partStream, pictureToInsert.RawFormat);
}
else
throw new ArgumentException("The xpath query did not return a valid location.");
document.MainDocumentPart.PutXDocument();
}
return streamDoc.GetModifiedDocument();
}
}
/// <summary>
/// Gets the image type representation for a mimetype
/// </summary>
/// <param name="format">Content mimetype</param>
/// <returns>Image type</returns>
private static ImagePartType GetImagePartType(ImageFormat format)
{
if (format.Equals(ImageFormat.Jpeg))
return ImagePartType.Jpeg;
else if (format.Equals(ImageFormat.Emf))
return ImagePartType.Emf;
else if (format.Equals(ImageFormat.Gif))
return ImagePartType.Gif;
else if (format.Equals(ImageFormat.Icon))
return ImagePartType.Icon;
else if (format.Equals(ImageFormat.Png))
return ImagePartType.Png;
else if (format.Equals(ImageFormat.Tiff))
return ImagePartType.Tiff;
else if (format.Equals(ImageFormat.Wmf))
return ImagePartType.Wmf;
else
return ImagePartType.Bmp;
}
}
}

View File

@@ -0,0 +1,544 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.IO;
using System.IO.Packaging;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Validation;
using System.Text;
using System.Text.RegularExpressions;
namespace OpenXmlPowerTools
{
/// <summary>
/// Contains extension methods to modify Open XML Documents
/// </summary>
public static class PowerToolsExtensions
{
public static void RemovePart(this OpenXmlPart part)
{
var parentParts = part.GetParentParts().ToList();
foreach (var parentPart in parentParts)
parentPart.DeletePart(part);
}
/// <summary>
/// Removes personal information from the document.
/// </summary>
/// <param name="document"></param>
public static OpenXmlPowerToolsDocument RemovePersonalInformation(WmlDocument doc)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
XNamespace x = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
XDocument extendedFileProperties = document.ExtendedFilePropertiesPart.GetXDocument();
extendedFileProperties.Elements(x + "Properties").Elements(x + "Company").Remove();
XElement totalTime = extendedFileProperties.Elements(x + "Properties").Elements(x + "TotalTime").FirstOrDefault();
if (totalTime != null)
totalTime.Value = "0";
document.ExtendedFilePropertiesPart.PutXDocument();
XNamespace dc = "http://purl.org/dc/elements/1.1/";
XNamespace cp = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
XDocument coreFileProperties = document.CoreFilePropertiesPart.GetXDocument();
foreach (var textNode in coreFileProperties.Elements(cp + "coreProperties")
.Elements(dc + "creator")
.Nodes()
.OfType<XText>())
textNode.Value = "";
foreach (var textNode in coreFileProperties.Elements(cp + "coreProperties")
.Elements(cp + "lastModifiedBy")
.Nodes()
.OfType<XText>())
textNode.Value = "";
foreach (var textNode in coreFileProperties.Elements(cp + "coreProperties")
.Elements(dc + "title")
.Nodes()
.OfType<XText>())
textNode.Value = "";
XElement revision = coreFileProperties.Elements(cp + "coreProperties").Elements(cp + "revision").FirstOrDefault();
if (revision != null)
revision.Value = "1";
document.CoreFilePropertiesPart.PutXDocument();
// add w:removePersonalInformation, w:removeDateAndTime to DocumentSettingsPart
XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
XDocument documentSettings = document.MainDocumentPart.DocumentSettingsPart.GetXDocument();
// add the new elements in the right position. Add them after the following three elements
// (which may or may not exist in the xml document).
XElement settings = documentSettings.Root;
XElement lastOfTop3 = settings.Elements()
.Where(e => e.Name == w + "writeProtection" ||
e.Name == w + "view" ||
e.Name == w + "zoom")
.InDocumentOrder()
.LastOrDefault();
if (lastOfTop3 == null)
{
// none of those three exist, so add as first children of the root element
settings.AddFirst(
settings.Elements(w + "removePersonalInformation").Any() ?
null :
new XElement(w + "removePersonalInformation"),
settings.Elements(w + "removeDateAndTime").Any() ?
null :
new XElement(w + "removeDateAndTime")
);
}
else
{
// one of those three exist, so add after the last one
lastOfTop3.AddAfterSelf(
settings.Elements(w + "removePersonalInformation").Any() ?
null :
new XElement(w + "removePersonalInformation"),
settings.Elements(w + "removeDateAndTime").Any() ?
null :
new XElement(w + "removeDateAndTime")
);
}
document.MainDocumentPart.DocumentSettingsPart.PutXDocument();
}
return streamDoc.GetModifiedDocument();
}
}
private static string StringConcatenate<T>(this IEnumerable<T> source, Func<T, string> func, string separator)
{
StringBuilder sb = new StringBuilder();
foreach (T item in source)
sb.Append(func(item)).Append(separator);
if (sb.Length > separator.Length)
sb.Length -= separator.Length;
return sb.ToString();
}
static string ContainsAnyStyles(IEnumerable<string> stylesToSearch, IEnumerable<string> searchStrings)
{
if (searchStrings == null)
return null;
foreach (var style in stylesToSearch)
foreach (var s in searchStrings)
if (String.Compare(style, s, true) == 0)
return s;
return null;
}
static string ContainsAnyContent(string stringToSearch, IEnumerable<string> searchStrings,
IEnumerable<Regex> regularExpressions, bool isRegularExpression, bool caseInsensitive)
{
if (searchStrings == null)
return null;
if (isRegularExpression)
{
foreach (var r in regularExpressions)
if (r.IsMatch(stringToSearch))
return r.ToString();
}
else
if (caseInsensitive)
{
foreach (var s in searchStrings)
if (stringToSearch.ToLower().Contains(s.ToLower()))
return s;
}
else
{
foreach (var s in searchStrings)
if (stringToSearch.Contains(s))
return s;
}
return null;
}
static IEnumerable<string> GetAllStyleIdsAndNames(WordprocessingDocument doc, string styleId)
{
string localStyleId = styleId;
XNamespace w =
"http://schemas.openxmlformats.org/wordprocessingml/2006/main";
yield return styleId;
string styleNameForFirstStyle = (string)doc
.MainDocumentPart
.StyleDefinitionsPart
.GetXDocument()
.Root
.Elements(w + "style")
.Where(e => (string)e.Attribute(w + "type") == "paragraph" &&
(string)e.Attribute(w + "styleId") == styleId)
.Elements(w + "name")
.Attributes(w + "val")
.FirstOrDefault();
if (styleNameForFirstStyle != null)
yield return styleNameForFirstStyle;
while (true)
{
XElement style = doc
.MainDocumentPart
.StyleDefinitionsPart
.GetXDocument()
.Root
.Elements(w + "style")
.Where(e => (string)e.Attribute(w + "type") == "paragraph" &&
(string)e.Attribute(w + "styleId") == localStyleId)
.FirstOrDefault();
if (style == null)
yield break;
var basedOn = (string)style
.Elements(w + "basedOn")
.Attributes(w + "val")
.FirstOrDefault();
if (basedOn == null)
yield break;
yield return basedOn;
XElement basedOnStyle = doc
.MainDocumentPart
.StyleDefinitionsPart
.GetXDocument()
.Root
.Elements(w + "style")
.Where(e => (string)e.Attribute(w + "type") == "paragraph" &&
(string)e.Attribute(w + "styleId") == basedOn)
.FirstOrDefault();
string basedOnStyleName = (string)basedOnStyle
.Elements(w + "name")
.Attributes(w + "val")
.FirstOrDefault();
if (basedOnStyleName != null)
yield return basedOnStyleName;
localStyleId = basedOn;
}
}
private static IEnumerable<string> GetInheritedStyles(WordprocessingDocument doc, string styleName)
{
string localStyleName = styleName;
XNamespace w =
"http://schemas.openxmlformats.org/wordprocessingml/2006/main";
yield return styleName;
while (true)
{
XElement style = doc
.MainDocumentPart
.StyleDefinitionsPart
.GetXDocument()
.Root
.Elements(w + "style")
.Where(e => (string)e.Attribute(w + "type") == "paragraph" &&
(string)e.Element(w + "name").Attribute(w + "val") == localStyleName)
.FirstOrDefault();
if (style == null)
yield break;
var basedOn = (string)style
.Elements(w + "basedOn")
.Attributes(w + "val")
.FirstOrDefault();
if (basedOn == null)
yield break;
yield return basedOn;
localStyleName = basedOn;
}
}
static public Commands.MatchInfo[] SearchInDocument(WmlDocument doc,
IEnumerable<string> styleSearchString, IEnumerable<string> contentSearchString,
bool isRegularExpression, bool caseInsensitive)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
XNamespace w =
"http://schemas.openxmlformats.org/wordprocessingml/2006/main";
XName r = w + "r";
XName ins = w + "ins";
RegexOptions options;
Regex[] regularExpressions = null;
if (isRegularExpression && contentSearchString != null)
{
if (caseInsensitive)
options = RegexOptions.IgnoreCase | RegexOptions.Compiled;
else
options = RegexOptions.Compiled;
regularExpressions = contentSearchString
.Select(s => new Regex(s, options)).ToArray();
}
var defaultStyleName = (string)document
.MainDocumentPart
.StyleDefinitionsPart
.GetXDocument()
.Root
.Elements(w + "style")
.Where(style =>
(string)style.Attribute(w + "type") == "paragraph" &&
(string)style.Attribute(w + "default") == "1")
.First()
.Attribute(w + "styleId");
var q1 = document
.MainDocumentPart
.GetXDocument()
.Root
.Element(w + "body")
.Elements()
.Select((p, i) =>
{
var styleNode = p
.Elements(w + "pPr")
.Elements(w + "pStyle")
.FirstOrDefault();
var styleName = styleNode != null ?
(string)styleNode.Attribute(w + "val") :
defaultStyleName;
return new
{
Element = p,
Index = i,
StyleName = styleName
};
}
);
var q2 = q1
.Select(i =>
{
string text = null;
if (i.Element.Name == w + "p")
text = i.Element.Elements()
.Where(z => z.Name == r || z.Name == ins)
.Descendants(w + "t")
.StringConcatenate(element => (string)element);
else
text = i.Element
.Descendants(w + "p")
.StringConcatenate(p => p
.Elements()
.Where(z => z.Name == r || z.Name == ins)
.Descendants(w + "t")
.StringConcatenate(element => (string)element),
Environment.NewLine
);
return new
{
Element = i.Element,
StyleName = i.StyleName,
Index = i.Index,
Text = text
};
}
);
var q3 = q2
.Select(i =>
new Commands.MatchInfo
{
ElementNumber = i.Index + 1,
Content = i.Text,
Style = ContainsAnyStyles(GetAllStyleIdsAndNames(document, i.StyleName).Distinct(), styleSearchString),
Pattern = ContainsAnyContent(i.Text, contentSearchString, regularExpressions, isRegularExpression, caseInsensitive),
IgnoreCase = caseInsensitive
}
)
.Where(i => (styleSearchString == null || i.Style != null) && (contentSearchString == null || i.Pattern != null));
return q3.ToArray();
}
}
public static OpenXmlPowerToolsDocument InsertXml(OpenXmlPowerToolsDocument doc, string[] partPaths, string insertionXpath, string content)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (Package package = streamDoc.GetPackage())
{
foreach (string partPath in partPaths)
{
Uri xmlPartUri;
XmlDocument xmlDocument;
PackagePart xmlPart = null;
// Searches for the given part
xmlPartUri = new Uri(partPath, UriKind.Relative);
//if (!document.Package.PartExists(xmlPartUri))
//throw new ArgumentException("Specified part does not exist.");
xmlPart = package.GetPart(xmlPartUri);
using (XmlReader xmlReader = XmlReader.Create(xmlPart.GetStream(FileMode.Open, FileAccess.Read)))
{
try
{
xmlDocument = new XmlDocument();
xmlDocument.Load(xmlReader);
}
catch (XmlException)
{
xmlDocument = new XmlDocument();
}
}
// Looks into the XmlDocument for nodes at the specified path
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(xmlDocument.NameTable);
namespaceManager.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
XmlNode insertionPoint =
xmlDocument.SelectSingleNode(insertionXpath, namespaceManager);
if (insertionPoint == null)
throw new ArgumentException("Insertion point does not exist.");
StringReader r = new StringReader("<w:node xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>" + content + "</w:node>");
XmlNode nodoid = xmlDocument.ReadNode(XmlReader.Create(r));
//doc.LoadXml("<w:node xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>" + xmlContent + "</w:node>");
//// Inserts new contents into the given part
XmlNode xmlNodeToInsert =
nodoid;// doc.FirstChild;
// xmlDocument.CreateElement("w","node", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
//xmlNodeToInsert. .InnerXml = xmlContent;
XmlNodeList nodes = xmlNodeToInsert.ChildNodes;
if (nodes.Count > 0)
for (int i = nodes.Count - 1; i >= 0; i--)
{
XmlNode node = nodes[i];
insertionPoint.ParentNode.InsertAfter(node, insertionPoint);
}
// Writes the XmlDocument back to the part
using (XmlWriter writer = XmlWriter.Create(xmlPart.GetStream(FileMode.Create, FileAccess.Write)))
{
xmlDocument.WriteTo(writer);
}
}
}
return streamDoc.GetModifiedDocument();
}
}
public static OpenXmlPowerToolsDocument Lock(WmlDocument doc)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
//Finds the settings part
XDocument settingsDocument;
XElement documentProtectionElement = null;
if (document.MainDocumentPart.DocumentSettingsPart == null)
{
//If settings part does not exist creates a new one
DocumentSettingsPart settingsPart = document.MainDocumentPart.AddNewPart<DocumentSettingsPart>();
settingsDocument = settingsPart.GetXDocument();
settingsDocument.Add(new XElement(W.settings,
new XAttribute(XNamespace.Xmlns + "w", W.w),
new XAttribute(XNamespace.Xmlns + "r", R.r)));
}
else
{
//If the settings part does exist looks if documentProtection has been included
settingsDocument = document.MainDocumentPart.DocumentSettingsPart.GetXDocument();
documentProtectionElement = settingsDocument.Element(W.settings).Element(W.documentProtection);
}
//Creates the documentProtection element, or edits it if it exists
if (documentProtectionElement == null)
{
settingsDocument
.Element(W.settings)
.Add(
new XElement(W.documentProtection,
new XAttribute(W.edit, "readOnly")
)
);
}
else
documentProtectionElement.SetAttributeValue(W.edit, "readOnly");
document.MainDocumentPart.DocumentSettingsPart.PutXDocument();
}
return streamDoc.GetModifiedDocument();
}
}
public static void SetContent(WordprocessingDocument document, IEnumerable<XElement> contents)
{
MainDocumentPart mainDocumentPart = document.MainDocumentPart;
if (mainDocumentPart == null)
mainDocumentPart = document.AddMainDocumentPart();
XDocument mainDocumentPartContentToInsert = new XDocument(
new XElement(W.document,
new XAttribute(XNamespace.Xmlns + "w", W.w),
new XAttribute(XNamespace.Xmlns + "r", R.r),
new XElement(W.body, contents)));
XDocument mainDocumentPartContent = mainDocumentPart.GetXDocument();
if (mainDocumentPartContent.Root == null)
mainDocumentPartContent.Add(mainDocumentPartContentToInsert.Root);
else
mainDocumentPartContent.Root.ReplaceWith(mainDocumentPartContentToInsert.Root);
mainDocumentPart.PutXDocument();
}
public static IEnumerable<ValidationErrorInfo> ValidateXml(OpenXmlPowerToolsDocument document)
{
if (document is WmlDocument)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(document))
using (WordprocessingDocument doc = streamDoc.GetWordprocessingDocument())
{
OpenXmlValidator validator = new OpenXmlValidator();
return validator.Validate(doc);
}
}
else if (document is SmlDocument)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(document))
using (SpreadsheetDocument doc = streamDoc.GetSpreadsheetDocument())
{
OpenXmlValidator validator = new OpenXmlValidator();
return validator.Validate(doc);
}
}
else if (document is PmlDocument)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(document))
using (PresentationDocument doc = streamDoc.GetPresentationDocument())
{
OpenXmlValidator validator = new OpenXmlValidator();
return validator.Validate(doc);
}
}
throw new PowerToolsDocumentException("Not an Open XML document.");
}
}
}

View File

@@ -0,0 +1,456 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.IO.Packaging;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
public class PowerToolsDocumentException : Exception
{
public PowerToolsDocumentException(string message) : base(message) { }
}
public class PowerToolsInvalidDataException : Exception
{
public PowerToolsInvalidDataException(string message) : base(message) { }
}
public class OpenXmlPowerToolsDocument
{
public string FileName { get; set; }
public byte[] DocumentByteArray { get; set; }
public static OpenXmlPowerToolsDocument FromFileName(string fileName)
{
byte[] bytes = File.ReadAllBytes(fileName);
Type type;
try
{
type = GetDocumentType(bytes);
}
catch (FileFormatException)
{
throw new PowerToolsDocumentException("Not an Open XML document.");
}
if (type == typeof(WordprocessingDocument))
return new WmlDocument(fileName, bytes);
if (type == typeof(SpreadsheetDocument))
return new SmlDocument(fileName, bytes);
if (type == typeof(PresentationDocument))
return new PmlDocument(fileName, bytes);
if (type == typeof(Package))
{
OpenXmlPowerToolsDocument pkg = new OpenXmlPowerToolsDocument(bytes);
pkg.FileName = fileName;
return pkg;
}
throw new PowerToolsDocumentException("Not an Open XML document.");
}
public static OpenXmlPowerToolsDocument FromDocument(OpenXmlPowerToolsDocument doc)
{
Type type = doc.GetDocumentType();
if (type == typeof(WordprocessingDocument))
return new WmlDocument(doc);
if (type == typeof(SpreadsheetDocument))
return new SmlDocument(doc);
if (type == typeof(PresentationDocument))
return new PmlDocument(doc);
return null; // This should not be possible from a valid OpenXmlPowerToolsDocument object
}
public OpenXmlPowerToolsDocument(OpenXmlPowerToolsDocument original)
{
DocumentByteArray = new byte[original.DocumentByteArray.Length];
Array.Copy(original.DocumentByteArray, DocumentByteArray, original.DocumentByteArray.Length);
FileName = original.FileName;
}
public OpenXmlPowerToolsDocument(string fileName)
{
this.FileName = fileName;
DocumentByteArray = File.ReadAllBytes(fileName);
}
public OpenXmlPowerToolsDocument(byte[] byteArray)
{
DocumentByteArray = new byte[byteArray.Length];
Array.Copy(byteArray, DocumentByteArray, byteArray.Length);
this.FileName = null;
}
public OpenXmlPowerToolsDocument(string fileName, MemoryStream memStream)
{
FileName = fileName;
DocumentByteArray = new byte[memStream.Length];
Array.Copy(memStream.GetBuffer(), DocumentByteArray, memStream.Length);
}
public string GetName()
{
if (FileName == null)
return "Unnamed Document";
FileInfo file = new FileInfo(FileName);
return file.Name;
}
public void SaveAs(string fileName)
{
File.WriteAllBytes(fileName, DocumentByteArray);
}
public void Save()
{
if (this.FileName == null)
throw new InvalidOperationException("Attempting to Save a document that has no file name. Use SaveAs instead.");
File.WriteAllBytes(this.FileName, DocumentByteArray);
}
public void WriteByteArray(Stream stream)
{
stream.Write(DocumentByteArray, 0, DocumentByteArray.Length);
}
public Type GetDocumentType()
{
return GetDocumentType(DocumentByteArray);
}
private static Type GetDocumentType(byte[] bytes)
{
using (MemoryStream stream = new MemoryStream(bytes))
using (Package package = Package.Open(stream, FileMode.Open))
{
PackageRelationship relationship = package.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument").FirstOrDefault();
if (relationship != null)
{
PackagePart part = package.GetPart(PackUriHelper.ResolvePartUri(relationship.SourceUri, relationship.TargetUri));
switch (part.ContentType)
{
case "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml":
return typeof(WordprocessingDocument);
case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml":
return typeof(SpreadsheetDocument);
case "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml":
return typeof(PresentationDocument);
}
return typeof(Package);
}
return null;
}
}
public static void SavePartAs(OpenXmlPart part, string filePath)
{
Stream partStream = part.GetStream(FileMode.Open, FileAccess.Read);
byte[] partContent = new byte[partStream.Length];
partStream.Read(partContent, 0, (int)partStream.Length);
File.WriteAllBytes(filePath, partContent);
}
}
public partial class WmlDocument : OpenXmlPowerToolsDocument
{
public WmlDocument(OpenXmlPowerToolsDocument original)
: base(original)
{
if (GetDocumentType() != typeof(WordprocessingDocument))
throw new PowerToolsDocumentException("Not a Wordprocessing document.");
}
public WmlDocument(string fileName)
: base(fileName)
{
if (GetDocumentType() != typeof(WordprocessingDocument))
throw new PowerToolsDocumentException("Not a Wordprocessing document.");
}
public WmlDocument(string fileName, byte[] byteArray)
: base(byteArray)
{
FileName = fileName;
if (GetDocumentType() != typeof(WordprocessingDocument))
throw new PowerToolsDocumentException("Not a Wordprocessing document.");
}
public WmlDocument(string fileName, MemoryStream memStream)
: base(fileName, memStream)
{
}
}
public partial class SmlDocument : OpenXmlPowerToolsDocument
{
public SmlDocument(OpenXmlPowerToolsDocument original)
: base(original)
{
if (GetDocumentType() != typeof(SpreadsheetDocument))
throw new PowerToolsDocumentException("Not a Spreadsheet document.");
}
public SmlDocument(string fileName)
: base(fileName)
{
if (GetDocumentType() != typeof(SpreadsheetDocument))
throw new PowerToolsDocumentException("Not a Spreadsheet document.");
}
public SmlDocument(string fileName, byte[] byteArray)
: base(byteArray)
{
FileName = fileName;
if (GetDocumentType() != typeof(SpreadsheetDocument))
throw new PowerToolsDocumentException("Not a Spreadsheet document.");
}
public SmlDocument(string fileName, MemoryStream memStream)
: base(fileName, memStream)
{
}
}
public partial class PmlDocument : OpenXmlPowerToolsDocument
{
public PmlDocument(OpenXmlPowerToolsDocument original)
: base(original)
{
if (GetDocumentType() != typeof(PresentationDocument))
throw new PowerToolsDocumentException("Not a Presentation document.");
}
public PmlDocument(string fileName)
: base(fileName)
{
if (GetDocumentType() != typeof(PresentationDocument))
throw new PowerToolsDocumentException("Not a Presentation document.");
}
public PmlDocument(string fileName, byte[] byteArray)
: base(byteArray)
{
FileName = fileName;
if (GetDocumentType() != typeof(PresentationDocument))
throw new PowerToolsDocumentException("Not a Presentation document.");
}
public PmlDocument(string fileName, MemoryStream memStream)
: base(fileName, memStream)
{
}
}
public class OpenXmlMemoryStreamDocument : IDisposable
{
private OpenXmlPowerToolsDocument Document;
private MemoryStream DocMemoryStream;
private Package DocPackage;
public OpenXmlMemoryStreamDocument(OpenXmlPowerToolsDocument doc)
{
Document = doc;
DocMemoryStream = new MemoryStream();
doc.WriteByteArray(DocMemoryStream);
try
{
DocPackage = Package.Open(DocMemoryStream, FileMode.Open);
}
catch (Exception)
{
throw new PowerToolsDocumentException("Not an Open XML document.");
}
}
internal OpenXmlMemoryStreamDocument(MemoryStream stream)
{
DocMemoryStream = stream;
try
{
DocPackage = Package.Open(DocMemoryStream, FileMode.Open);
}
catch (Exception)
{
throw new PowerToolsDocumentException("Not an Open XML document.");
}
}
public static OpenXmlMemoryStreamDocument CreateWordprocessingDocument()
{
MemoryStream stream = new MemoryStream();
using (WordprocessingDocument doc = WordprocessingDocument.Create(stream, DocumentFormat.OpenXml.WordprocessingDocumentType.Document))
{
doc.AddMainDocumentPart();
doc.MainDocumentPart.PutXDocument(new XDocument(
new XElement(W.document,
new XAttribute(XNamespace.Xmlns + "w", W.w),
new XAttribute(XNamespace.Xmlns + "r", R.r),
new XElement(W.body))));
doc.Close();
return new OpenXmlMemoryStreamDocument(stream);
}
}
public static OpenXmlMemoryStreamDocument CreateSpreadsheetDocument()
{
MemoryStream stream = new MemoryStream();
using (SpreadsheetDocument doc = SpreadsheetDocument.Create(stream, DocumentFormat.OpenXml.SpreadsheetDocumentType.Workbook))
{
doc.AddWorkbookPart();
XNamespace ns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
XNamespace relationshipsns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
doc.WorkbookPart.PutXDocument(new XDocument(
new XElement(ns + "workbook",
new XAttribute("xmlns", ns),
new XAttribute(XNamespace.Xmlns + "r", relationshipsns),
new XElement(ns + "sheets"))));
doc.Close();
return new OpenXmlMemoryStreamDocument(stream);
}
}
public static OpenXmlMemoryStreamDocument CreatePackage()
{
MemoryStream stream = new MemoryStream();
Package package = Package.Open(stream, FileMode.Create);
package.Close();
return new OpenXmlMemoryStreamDocument(stream);
}
public Package GetPackage()
{
return DocPackage;
}
public WordprocessingDocument GetWordprocessingDocument()
{
try
{
if (GetDocumentType() != typeof(WordprocessingDocument))
throw new PowerToolsDocumentException("Not a Wordprocessing document.");
return WordprocessingDocument.Open(DocPackage);
}
catch (Exception)
{
throw new PowerToolsDocumentException("Not a Wordprocessing document.");
}
}
public SpreadsheetDocument GetSpreadsheetDocument()
{
try
{
if (GetDocumentType() != typeof(SpreadsheetDocument))
throw new PowerToolsDocumentException("Not a Spreadsheet document.");
return SpreadsheetDocument.Open(DocPackage);
}
catch (Exception)
{
throw new PowerToolsDocumentException("Not a Spreadsheet document.");
}
}
public PresentationDocument GetPresentationDocument()
{
try
{
if (GetDocumentType() != typeof(PresentationDocument))
throw new PowerToolsDocumentException("Not a Presentation document.");
return PresentationDocument.Open(DocPackage);
}
catch (Exception)
{
throw new PowerToolsDocumentException("Not a Presentation document.");
}
}
public Type GetDocumentType()
{
PackageRelationship relationship = DocPackage.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument").FirstOrDefault();
if (relationship == null)
throw new PowerToolsDocumentException("Not an Open XML Document.");
PackagePart part = DocPackage.GetPart(PackUriHelper.ResolvePartUri(relationship.SourceUri, relationship.TargetUri));
switch (part.ContentType)
{
case "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml":
return typeof(WordprocessingDocument);
case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml":
return typeof(SpreadsheetDocument);
case "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml":
return typeof(PresentationDocument);
}
return null;
}
public OpenXmlPowerToolsDocument GetModifiedDocument()
{
DocPackage.Close();
DocPackage = null;
return new OpenXmlPowerToolsDocument((Document == null) ? null : Document.FileName, DocMemoryStream);
}
public WmlDocument GetModifiedWmlDocument()
{
DocPackage.Close();
DocPackage = null;
return new WmlDocument((Document == null) ? null : Document.FileName, DocMemoryStream);
}
public SmlDocument GetModifiedSmlDocument()
{
DocPackage.Close();
DocPackage = null;
return new SmlDocument((Document == null) ? null : Document.FileName, DocMemoryStream);
}
public PmlDocument GetModifiedPmlDocument()
{
DocPackage.Close();
DocPackage = null;
return new PmlDocument((Document == null) ? null : Document.FileName, DocMemoryStream);
}
public void Close()
{
Dispose(true);
}
public void Dispose()
{
Dispose(true);
}
~OpenXmlMemoryStreamDocument()
{
Dispose(false);
}
private void Dispose(Boolean disposing)
{
if (disposing)
{
if (DocPackage != null)
{
DocPackage.Close();
}
if (DocMemoryStream != null)
{
DocMemoryStream.Dispose();
}
}
if (DocPackage == null && DocMemoryStream == null)
return;
DocPackage = null;
DocMemoryStream = null;
GC.SuppressFinalize(this);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,219 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license
can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace OpenXmlPowerTools
{
public static class PtExtensions
{
public static string StringConcatenate(this IEnumerable<string> source)
{
StringBuilder sb = new StringBuilder();
foreach (string s in source)
sb.Append(s);
return sb.ToString();
}
public static string StringConcatenate<T>(
this IEnumerable<T> source,
Func<T, string> projectionFunc)
{
return source.Aggregate(
new StringBuilder(),
(s, i) => s.Append(projectionFunc(i)),
s => s.ToString());
}
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TSecond, TResult> func)
{
var ie1 = first.GetEnumerator();
var ie2 = second.GetEnumerator();
while (ie1.MoveNext() && ie2.MoveNext())
yield return func(ie1.Current, ie2.Current);
}
public static IEnumerable<IGrouping<TKey, TSource>> GroupAdjacent<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector)
{
TKey last = default(TKey);
bool haveLast = false;
List<TSource> list = new List<TSource>();
foreach (TSource s in source)
{
TKey k = keySelector(s);
if (haveLast)
{
if (!k.Equals(last))
{
yield return new GroupOfAdjacent<TSource, TKey>(list, last);
list = new List<TSource>();
list.Add(s);
last = k;
}
else
{
list.Add(s);
last = k;
}
}
else
{
list.Add(s);
last = k;
haveLast = true;
}
}
if (haveLast)
yield return new GroupOfAdjacent<TSource, TKey>(list, last);
}
private static void InitializeReverseDocumentOrder(XElement element)
{
XElement prev = null;
foreach (XElement e in element.Elements())
{
e.AddAnnotation(new ReverseDocumentOrderInfo { PreviousSibling = prev });
prev = e;
}
}
public static IEnumerable<XElement> ElementsBeforeSelfReverseDocumentOrder(
this XElement element)
{
if (element.Annotation<ReverseDocumentOrderInfo>() == null)
InitializeReverseDocumentOrder(element.Parent);
XElement current = element;
while (true)
{
XElement previousElement = current
.Annotation<ReverseDocumentOrderInfo>()
.PreviousSibling;
if (previousElement == null)
yield break;
yield return previousElement;
current = previousElement;
}
}
public static string ToStringNewLineOnAttributes(this XElement element)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.NewLineOnAttributes = true;
StringBuilder stringBuilder = new StringBuilder();
using (StringWriter stringWriter = new StringWriter(stringBuilder))
using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, settings))
element.WriteTo(xmlWriter);
return stringBuilder.ToString();
}
public static IEnumerable<XElement> DescendantsTrimmed(this XElement element,
XName trimName)
{
return DescendantsTrimmed(element, e => e.Name == trimName);
}
public static IEnumerable<XElement> DescendantsTrimmed(this XElement element,
Func<XElement, bool> predicate)
{
Stack<IEnumerator<XElement>> iteratorStack = new Stack<IEnumerator<XElement>>();
iteratorStack.Push(element.Elements().GetEnumerator());
while (iteratorStack.Count > 0)
{
while (iteratorStack.Peek().MoveNext())
{
XElement currentXElement = iteratorStack.Peek().Current;
if (predicate(currentXElement))
{
yield return currentXElement;
continue;
}
yield return currentXElement;
iteratorStack.Push(currentXElement.Elements().GetEnumerator());
}
iteratorStack.Pop();
}
}
public static IEnumerable<TResult> Rollup<TSource, TResult>(
this IEnumerable<TSource> source,
TResult seed,
Func<TSource, TResult, TResult> projection)
{
TResult nextSeed = seed;
foreach (TSource src in source)
{
TResult projectedValue = projection(src, nextSeed);
nextSeed = projectedValue;
yield return projectedValue;
}
}
public static IEnumerable<TSource> SequenceAt<TSource>(this TSource[] source, int index)
{
int i = index;
while (i < source.Length)
yield return source[i++];
}
}
public class ReverseDocumentOrderInfo
{
public XElement PreviousSibling;
}
public class GroupOfAdjacent<TSource, TKey> : IEnumerable<TSource>, IGrouping<TKey, TSource>
{
public TKey Key { get; set; }
private List<TSource> GroupList { get; set; }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((System.Collections.Generic.IEnumerable<TSource>)this).GetEnumerator();
}
System.Collections.Generic.IEnumerator<TSource>
System.Collections.Generic.IEnumerable<TSource>.GetEnumerator()
{
foreach (var s in GroupList)
yield return s;
}
public GroupOfAdjacent(List<TSource> source, TKey key)
{
GroupList = source;
Key = key;
}
}
public class XEntity : XText
{
public override void WriteTo(XmlWriter writer)
{
writer.WriteEntityRef(this.Value);
}
public XEntity(string value) : base(value) { }
}
}

View File

@@ -0,0 +1,647 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license
can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
public partial class WmlDocument : OpenXmlPowerToolsDocument
{
public WmlDocument AddToc(string xPath, string switches, string title, int? rightTabPos)
{
return (WmlDocument)ReferenceAdder.AddToc(this, xPath, switches, title, rightTabPos);
}
public WmlDocument AddTof(string xPath, string switches, int? rightTabPos)
{
return (WmlDocument)ReferenceAdder.AddTof(this, xPath, switches, rightTabPos);
}
public WmlDocument AddToa(string xPath, string switches, int? rightTabPos)
{
return (WmlDocument)ReferenceAdder.AddToa(this, xPath, switches, rightTabPos);
}
}
public class ReferenceAdder
{
public static WmlDocument AddToc(WmlDocument document, string xPath, string switches, string title, int? rightTabPos)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(document))
{
using (WordprocessingDocument doc = streamDoc.GetWordprocessingDocument())
{
AddToc(doc, xPath, switches, title, rightTabPos);
}
return streamDoc.GetModifiedWmlDocument();
}
}
public static void AddToc(WordprocessingDocument doc, string xPath, string switches, string title, int? rightTabPos)
{
UpdateFontTablePart(doc);
UpdateStylesPartForToc(doc);
UpdateStylesWithEffectsPartForToc(doc);
if (title == null)
title = "Contents";
if (rightTabPos == null)
rightTabPos = 9350;
// {0} tocTitle (default = "Contents")
// {1} rightTabPosition (default = 9350)
// {2} switches
String xmlString =
@"<w:sdt xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:sdtPr>
<w:docPartObj>
<w:docPartGallery w:val='Table of Contents'/>
<w:docPartUnique/>
</w:docPartObj>
</w:sdtPr>
<w:sdtEndPr>
<w:rPr>
<w:rFonts w:asciiTheme='minorHAnsi' w:cstheme='minorBidi' w:eastAsiaTheme='minorHAnsi' w:hAnsiTheme='minorHAnsi'/>
<w:color w:val='auto'/>
<w:sz w:val='22'/>
<w:szCs w:val='22'/>
<w:lang w:eastAsia='en-US'/>
</w:rPr>
</w:sdtEndPr>
<w:sdtContent>
<w:p>
<w:pPr>
<w:pStyle w:val='TOCHeading'/>
</w:pPr>
<w:r>
<w:t>{0}</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val='TOC1'/>
<w:tabs>
<w:tab w:val='right' w:leader='dot' w:pos='{1}'/>
</w:tabs>
<w:rPr>
<w:noProof/>
</w:rPr>
</w:pPr>
<w:r>
<w:fldChar w:fldCharType='begin' w:dirty='true'/>
</w:r>
<w:r>
<w:instrText xml:space='preserve'> {2} </w:instrText>
</w:r>
<w:r>
<w:fldChar w:fldCharType='separate'/>
</w:r>
</w:p>
<w:p>
<w:r>
<w:rPr>
<w:b/>
<w:bCs/>
<w:noProof/>
</w:rPr>
<w:fldChar w:fldCharType='end'/>
</w:r>
</w:p>
</w:sdtContent>
</w:sdt>";
XmlReader sdtReader = XmlReader.Create(new StringReader(String.Format(xmlString, title, rightTabPos, switches)));
XElement sdt = XElement.Load(sdtReader);
XmlNamespaceManager namespaceManager;
XDocument mainXDoc = doc.MainDocumentPart.GetXDocument(out namespaceManager);
namespaceManager.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
XElement addBefore = mainXDoc.XPathSelectElement(xPath, namespaceManager);
if (addBefore == null)
throw new OpenXmlPowerToolsException("XPath expression did not select an element");
addBefore.AddBeforeSelf(sdt);
doc.MainDocumentPart.PutXDocument();
XDocument settingsXDoc = doc.MainDocumentPart.DocumentSettingsPart.GetXDocument();
XElement updateFields = settingsXDoc.Descendants(W.updateFields).FirstOrDefault();
if (updateFields != null)
updateFields.Attribute(W.val).Value = "true";
else
{
updateFields = new XElement(W.updateFields,
new XAttribute(W.val, "true"));
settingsXDoc.Root.Add(updateFields);
}
doc.MainDocumentPart.DocumentSettingsPart.PutXDocument();
}
public static WmlDocument AddTof(WmlDocument document, string xPath, string switches, int? rightTabPos)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(document))
{
using (WordprocessingDocument doc = streamDoc.GetWordprocessingDocument())
{
AddTof(doc, xPath, switches, rightTabPos);
}
return streamDoc.GetModifiedWmlDocument();
}
}
public static void AddTof(WordprocessingDocument doc, string xPath, string switches, int? rightTabPos)
{
UpdateFontTablePart(doc);
UpdateStylesPartForTof(doc);
UpdateStylesWithEffectsPartForTof(doc);
if (rightTabPos == null)
rightTabPos = 9350;
// {0} rightTabPosition (default = 9350)
// {1} switches
string xmlString =
@"<w:p xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:pPr>
<w:pStyle w:val='TableofFigures'/>
<w:tabs>
<w:tab w:val='right' w:leader='dot' w:pos='{0}'/>
</w:tabs>
<w:rPr>
<w:noProof/>
</w:rPr>
</w:pPr>
<w:r>
<w:fldChar w:fldCharType='begin' dirty='true'/>
</w:r>
<w:r>
<w:instrText xml:space='preserve'> {1} </w:instrText>
</w:r>
<w:r>
<w:fldChar w:fldCharType='separate'/>
</w:r>
<w:r>
<w:fldChar w:fldCharType='end'/>
</w:r>
</w:p>";
XDocument mainXDoc = doc.MainDocumentPart.GetXDocument();
XmlReader paragraphReader = XmlReader.Create(new StringReader(String.Format(xmlString, rightTabPos, switches)));
XElement paragraph = XElement.Load(paragraphReader);
XmlNameTable nameTable = paragraphReader.NameTable;
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(nameTable);
namespaceManager.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
XElement addBefore = mainXDoc.XPathSelectElement(xPath, namespaceManager);
if (addBefore == null)
throw new OpenXmlPowerToolsException("XPath expression did not select an element");
addBefore.AddBeforeSelf(paragraph);
doc.MainDocumentPart.PutXDocument();
XDocument settingsXDoc = doc.MainDocumentPart.DocumentSettingsPart.GetXDocument();
XElement updateFields = settingsXDoc.Descendants(W.updateFields).FirstOrDefault();
if (updateFields != null)
updateFields.Attribute(W.val).Value = "true";
else
{
updateFields = new XElement(W.updateFields,
new XAttribute(W.val, "true"));
settingsXDoc.Root.Add(updateFields);
}
doc.MainDocumentPart.DocumentSettingsPart.PutXDocument();
}
public static WmlDocument AddToa(WmlDocument document, string xPath, string switches, int? rightTabPos)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(document))
{
using (WordprocessingDocument doc = streamDoc.GetWordprocessingDocument())
{
AddToa(doc, xPath, switches, rightTabPos);
}
return streamDoc.GetModifiedWmlDocument();
}
}
public static void AddToa(WordprocessingDocument doc, string xPath, string switches, int? rightTabPos)
{
UpdateFontTablePart(doc);
UpdateStylesPartForToa(doc);
UpdateStylesWithEffectsPartForToa(doc);
if (rightTabPos == null)
rightTabPos = 9350;
// {0} rightTabPosition (default = 9350)
// {1} switches
string xmlString =
@"<w:p xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:pPr>
<w:pStyle w:val='TOAHeading'/>
<w:tabs>
<w:tab w:val='right'
w:leader='dot'
w:pos='{0}'/>
</w:tabs>
<w:rPr>
<w:rFonts w:asciiTheme='minorHAnsi'
w:eastAsiaTheme='minorEastAsia'
w:hAnsiTheme='minorHAnsi'
w:cstheme='minorBidi'/>
<w:b w:val='0'/>
<w:bCs w:val='0'/>
<w:noProof/>
<w:sz w:val='22'/>
<w:szCs w:val='22'/>
</w:rPr>
</w:pPr>
<w:r>
<w:fldChar w:fldCharType='begin'/>
</w:r>
<w:r>
<w:instrText xml:space='preserve'> {1} </w:instrText>
</w:r>
<w:r>
<w:fldChar w:fldCharType='separate'/>
</w:r>
<w:r>
<w:fldChar w:fldCharType='end'/>
</w:r>
</w:p>";
XDocument mainXDoc = doc.MainDocumentPart.GetXDocument();
XmlReader paragraphReader = XmlReader.Create(new StringReader(String.Format(xmlString, rightTabPos, switches)));
XElement paragraph = XElement.Load(paragraphReader);
XmlNameTable nameTable = paragraphReader.NameTable;
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(nameTable);
namespaceManager.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
XElement addBefore = mainXDoc.XPathSelectElement(xPath, namespaceManager);
if (addBefore == null)
throw new OpenXmlPowerToolsException("XPath expression did not select an element");
addBefore.AddBeforeSelf(paragraph);
doc.MainDocumentPart.PutXDocument();
XDocument settingsXDoc = doc.MainDocumentPart.DocumentSettingsPart.GetXDocument();
XElement updateFields = settingsXDoc.Descendants(W.updateFields).FirstOrDefault();
if (updateFields != null)
updateFields.Attribute(W.val).Value = "true";
else
{
updateFields = new XElement(W.updateFields,
new XAttribute(W.val, "true"));
settingsXDoc.Root.Add(updateFields);
}
doc.MainDocumentPart.DocumentSettingsPart.PutXDocument();
}
private static void AddElementIfMissing(XDocument partXDoc, XElement existing, string newElement)
{
if (existing != null)
return;
XElement newXElement = XElement.Parse(newElement);
newXElement.Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
partXDoc.Root.Add(newXElement);
}
private static void UpdateFontTablePart(WordprocessingDocument doc)
{
FontTablePart fontTablePart = doc.MainDocumentPart.FontTablePart;
if (fontTablePart == null)
throw new Exception("Todo need to insert font table part");
XDocument fontTableXDoc = fontTablePart.GetXDocument();
AddElementIfMissing(fontTableXDoc,
fontTableXDoc
.Root
.Elements(W.font)
.Where(e => (string)e.Attribute(W.name) == "Tahoma")
.FirstOrDefault(),
@"<w:font w:name='Tahoma' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:panose1 w:val='020B0604030504040204'/>
<w:charset w:val='00'/>
<w:family w:val='swiss'/>
<w:pitch w:val='variable'/>
<w:sig w:usb0='E1002EFF' w:usb1='C000605B' w:usb2='00000029' w:usb3='00000000' w:csb0='000101FF' w:csb1='00000000'/>
</w:font>");
fontTablePart.PutXDocument();
}
private static void UpdatePartForToc(OpenXmlPart part)
{
XDocument xDoc = part.GetXDocument();
AddElementIfMissing(
xDoc,
xDoc.Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "TOCHeading")
.FirstOrDefault(),
@"<w:style w:type='paragraph' w:styleId='TOCHeading' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:name w:val='TOC Heading'/>
<w:basedOn w:val='Heading1'/>
<w:next w:val='Normal'/>
<w:uiPriority w:val='39'/>
<w:semiHidden/>
<w:unhideWhenUsed/>
<w:qFormat/>
<w:pPr>
<w:outlineLvl w:val='9'/>
</w:pPr>
<w:rPr>
<w:lang w:eastAsia='ja-JP'/>
</w:rPr>
</w:style>");
AddElementIfMissing(
xDoc,
xDoc.Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "TOC1")
.FirstOrDefault(),
@"<w:style w:type='paragraph' w:styleId='TOC1' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:name w:val='toc 1'/>
<w:basedOn w:val='Normal'/>
<w:next w:val='Normal'/>
<w:autoRedefine/>
<w:uiPriority w:val='39'/>
<w:unhideWhenUsed/>
<w:pPr>
<w:spacing w:after='100'/>
</w:pPr>
</w:style>");
AddElementIfMissing(
xDoc,
xDoc.Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "TOC2")
.FirstOrDefault(),
@"<w:style w:type='paragraph' w:styleId='TOC2' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:name w:val='toc 2'/>
<w:basedOn w:val='Normal'/>
<w:next w:val='Normal'/>
<w:autoRedefine/>
<w:uiPriority w:val='39'/>
<w:unhideWhenUsed/>
<w:pPr>
<w:spacing w:after='100'/>
<w:ind w:left='220'/>
</w:pPr>
</w:style>");
AddElementIfMissing(
xDoc,
xDoc.Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "TOC3")
.FirstOrDefault(),
@"<w:style w:type='paragraph' w:styleId='TOC3' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:name w:val='toc 3'/>
<w:basedOn w:val='Normal'/>
<w:next w:val='Normal'/>
<w:autoRedefine/>
<w:uiPriority w:val='39'/>
<w:unhideWhenUsed/>
<w:pPr>
<w:spacing w:after='100'/>
<w:ind w:left='440'/>
</w:pPr>
</w:style>");
AddElementIfMissing(
xDoc,
xDoc.Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "TOC4")
.FirstOrDefault(),
@"<w:style w:type='paragraph' w:styleId='TOC4' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:name w:val='toc 4'/>
<w:basedOn w:val='Normal'/>
<w:next w:val='Normal'/>
<w:autoRedefine/>
<w:uiPriority w:val='39'/>
<w:unhideWhenUsed/>
<w:pPr>
<w:spacing w:after='100'/>
<w:ind w:left='660'/>
</w:pPr>
</w:style>");
AddElementIfMissing(
xDoc,
xDoc.Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.type) == "character" && (string)e.Attribute(W.styleId) == "Hyperlink")
.FirstOrDefault(),
@"<w:style w:type='character' w:styleId='Hyperlink' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:name w:val='Hyperlink'/>
<w:basedOn w:val='DefaultParagraphFont'/>
<w:uiPriority w:val='99'/>
<w:unhideWhenUsed/>
<w:rPr>
<w:color w:val='0000FF' w:themeColor='hyperlink'/>
<w:u w:val='single'/>
</w:rPr>
</w:style>");
AddElementIfMissing(
xDoc,
xDoc.Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "BalloonText")
.FirstOrDefault(),
@"<w:style w:type='paragraph' w:styleId='BalloonText' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:name w:val='Balloon Text'/>
<w:basedOn w:val='Normal'/>
<w:link w:val='BalloonTextChar'/>
<w:uiPriority w:val='99'/>
<w:semiHidden/>
<w:unhideWhenUsed/>
<w:pPr>
<w:spacing w:after='0' w:line='240' w:lineRule='auto'/>
</w:pPr>
<w:rPr>
<w:rFonts w:ascii='Tahoma' w:hAnsi='Tahoma' w:cs='Tahoma'/>
<w:sz w:val='16'/>
<w:szCs w:val='16'/>
</w:rPr>
</w:style>");
AddElementIfMissing(
xDoc,
xDoc.Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.type) == "character" &&
(bool?)e.Attribute(W.customStyle) == true && (string)e.Attribute(W.styleId) == "BalloonTextChar")
.FirstOrDefault(),
@"<w:style w:type='character' w:customStyle='1' w:styleId='BalloonTextChar' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:name w:val='Balloon Text Char'/>
<w:basedOn w:val='DefaultParagraphFont'/>
<w:link w:val='BalloonText'/>
<w:uiPriority w:val='99'/>
<w:semiHidden/>
<w:rPr>
<w:rFonts w:ascii='Tahoma' w:hAnsi='Tahoma' w:cs='Tahoma'/>
<w:sz w:val='16'/>
<w:szCs w:val='16'/>
</w:rPr>
</w:style>");
part.PutXDocument();
}
private static void UpdateStylesPartForToc(WordprocessingDocument doc)
{
StylesPart stylesPart = doc.MainDocumentPart.StyleDefinitionsPart;
if (stylesPart == null)
return;
UpdatePartForToc(stylesPart);
}
private static void UpdateStylesWithEffectsPartForToc(WordprocessingDocument doc)
{
StylesWithEffectsPart stylesWithEffectsPart = doc.MainDocumentPart.StylesWithEffectsPart;
if (stylesWithEffectsPart == null)
return;
UpdatePartForToc(stylesWithEffectsPart);
}
private static void UpdatePartForTof(OpenXmlPart part)
{
XDocument xDoc = part.GetXDocument();
AddElementIfMissing(
xDoc,
xDoc.Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "TableofFigures")
.FirstOrDefault(),
@"<w:style w:type='paragraph' w:styleId='TableofFigures' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:name w:val='table of figures'/>
<w:basedOn w:val='Normal'/>
<w:next w:val='Normal'/>
<w:uiPriority w:val='99'/>
<w:unhideWhenUsed/>
<w:pPr>
<w:spacing w:after='0'/>
</w:pPr>
</w:style>");
AddElementIfMissing(
xDoc,
xDoc.Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.type) == "character" && (string)e.Attribute(W.styleId) == "Hyperlink")
.FirstOrDefault(),
@"<w:style w:type='character' w:styleId='Hyperlink' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:name w:val='Hyperlink'/>
<w:basedOn w:val='DefaultParagraphFont'/>
<w:uiPriority w:val='99'/>
<w:unhideWhenUsed/>
<w:rPr>
<w:color w:val='0000FF' w:themeColor='hyperlink'/>
<w:u w:val='single'/>
</w:rPr>
</w:style>");
part.PutXDocument();
}
private static void UpdateStylesPartForTof(WordprocessingDocument doc)
{
StylesPart stylesPart = doc.MainDocumentPart.StyleDefinitionsPart;
if (stylesPart == null)
return;
UpdatePartForTof(stylesPart);
}
private static void UpdateStylesWithEffectsPartForTof(WordprocessingDocument doc)
{
StylesWithEffectsPart stylesWithEffectsPart = doc.MainDocumentPart.StylesWithEffectsPart;
if (stylesWithEffectsPart == null)
return;
UpdatePartForTof(stylesWithEffectsPart);
}
private static void UpdatePartForToa(OpenXmlPart part)
{
XDocument xDoc = part.GetXDocument();
AddElementIfMissing(
xDoc,
xDoc.Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "TableofAuthorities")
.FirstOrDefault(),
@"<w:style w:type='paragraph'
w:styleId='TableofAuthorities'
xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:name w:val='table of authorities'/>
<w:basedOn w:val='Normal'/>
<w:next w:val='Normal'/>
<w:uiPriority w:val='99'/>
<w:semiHidden/>
<w:unhideWhenUsed/>
<w:rsid w:val='0090569D'/>
<w:pPr>
<w:spacing w:after='0'/>
<w:ind w:left='220'
w:hanging='220'/>
</w:pPr>
</w:style>");
AddElementIfMissing(
xDoc,
xDoc.Root.Elements(W.style)
.Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "TOAHeading")
.FirstOrDefault(),
@"<w:style w:type='paragraph'
w:styleId='TOAHeading'
xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
<w:name w:val='toa heading'/>
<w:basedOn w:val='Normal'/>
<w:next w:val='Normal'/>
<w:uiPriority w:val='99'/>
<w:semiHidden/>
<w:unhideWhenUsed/>
<w:rsid w:val='0090569D'/>
<w:pPr>
<w:spacing w:before='120'/>
</w:pPr>
<w:rPr>
<w:rFonts w:asciiTheme='majorHAnsi'
w:eastAsiaTheme='majorEastAsia'
w:hAnsiTheme='majorHAnsi'
w:cstheme='majorBidi'/>
<w:b/>
<w:bCs/>
<w:sz w:val='24'/>
<w:szCs w:val='24'/>
</w:rPr>
</w:style>");
part.PutXDocument();
}
private static void UpdateStylesPartForToa(WordprocessingDocument doc)
{
StylesPart stylesPart = doc.MainDocumentPart.StyleDefinitionsPart;
if (stylesPart == null)
return;
UpdatePartForToa(stylesPart);
}
private static void UpdateStylesWithEffectsPartForToa(WordprocessingDocument doc)
{
StylesWithEffectsPart stylesWithEffectsPart = doc.MainDocumentPart.StylesWithEffectsPart;
if (stylesWithEffectsPart == null)
return;
UpdatePartForToa(stylesWithEffectsPart);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.Linq;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
/// <summary>
/// Provides access to setting operations
/// </summary>
public class SettingAccessor
{
private static XNamespace ns;
private static XNamespace settingsns;
private static XNamespace relationshipns;
static SettingAccessor()
{
ns = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
settingsns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
relationshipns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
}
/// <summary>
/// Nodes list with displayBackgroundShape elements
/// </summary>
public static XElement DisplayBackgroundShapeElements(WordprocessingDocument document)
{
XDocument settingsDocument = document.MainDocumentPart.DocumentSettingsPart.GetXDocument();
return settingsDocument.Descendants(settingsns + "displayBackgroundShape").FirstOrDefault();
}
/// <summary>
/// Adds a displayBackgroundShape element to the settings file
/// </summary>
public static void AddBackgroundShapeElement(WordprocessingDocument document)
{
XDocument settingsDocument = document.MainDocumentPart.DocumentSettingsPart.GetXDocument();
settingsDocument.Root.Add(
new XElement(ns + "displayBackgroundShape")
);
document.MainDocumentPart.DocumentSettingsPart.PutXDocument();
}
/// <summary>
/// Adds a the evenAndOddHeaders element, which allows to define distinct headers and footers for odd and even pages
/// </summary>
public static void AddEvenAndOddHeadersElement(WordprocessingDocument document)
{
XDocument settingsDocument = document.MainDocumentPart.DocumentSettingsPart.GetXDocument();
if (settingsDocument.Descendants(ns + "evenAndOddHeaders").FirstOrDefault() == null)
{
settingsDocument.Root.Add(
new XElement(ns + "evenAndOddHeaders"));
document.MainDocumentPart.DocumentSettingsPart.PutXDocument();
}
}
/// <summary>
/// Creates an empty base structure for a settings part
/// </summary>
/// <returns></returns>
private static XDocument CreateEmptySettings()
{
XDocument document =
new XDocument(
new XElement(ns + "settings",
new XAttribute(XNamespace.Xmlns + "w", ns),
new XAttribute(XNamespace.Xmlns + "r", relationshipns)
)
);
return document;
}
}
}

View File

@@ -0,0 +1,96 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.Linq;
using System.Xml.Linq;
using System.Xml;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
/// <summary>
/// Class to manage the Style Part for an SpreadSheetML document
/// </summary>
public class SpreadSheetStyleAccessor
{
private static XNamespace ns;
/// <summary>
/// Static constructor
/// </summary>
static SpreadSheetStyleAccessor()
{
ns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
}
/// <summary>
/// XDocument containing Xml content of the styles part
/// </summary>
public static XDocument GetStylesDocument(SpreadsheetDocument document)
{
if (document.WorkbookPart.WorkbookStylesPart != null)
return document.WorkbookPart.WorkbookStylesPart.GetXDocument();
else
return null;
}
/// <summary>
/// Sets a new styles part inside the document
/// </summary>
/// <param name="newStylesDocument">Path of styles definition file</param>
public static void SetStylePart(SpreadsheetDocument document, XDocument newStylesDocument)
{
try
{
// Replaces XDocument with the style file to transfer
XDocument stylesDocument = GetStylesDocument(document);
if (stylesDocument == null)
{
WorkbookStylesPart stylesPart =
document.WorkbookPart.AddNewPart<WorkbookStylesPart>();
stylesDocument = stylesPart.GetXDocument();
}
if (stylesDocument.Root == null)
stylesDocument.Add(newStylesDocument.Root);
else
stylesDocument.Root.ReplaceWith(newStylesDocument.Root);
document.WorkbookPart.WorkbookStylesPart.PutXDocument();
}
catch (XmlException ex)
{
throw new XmlException("File specified is not a valid XML file", ex);
}
}
/// <summary>
/// Returns the index inside the style part for a specific cell style
/// </summary>
/// <param name="cellStyle">Name for cell style to return the index of</param>
/// <returns></returns>
public static int GetCellStyleIndex(SpreadsheetDocument document, string cellStyle)
{
XDocument stylesXDocument = GetStylesDocument(document);
if (stylesXDocument == null)
return -1;
var cellStyleXElement =
stylesXDocument.Root
.Element(ns + "cellStyles")
.Elements(ns + "cellStyle")
.Where(c=> c.Attribute("name").Value.ToLower().Equals(cellStyle.ToLower())).FirstOrDefault<XElement>();
if (cellStyleXElement != null)
{
return System.Convert.ToInt32(cellStyleXElement.Attribute("xfId").Value);
}
return -1;
}
}
}

View File

@@ -0,0 +1,180 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
using System;
using System.Xml;
namespace OpenXmlPowerTools
{
/// <summary>
/// Class for working with the Table Definition Part for a SpreadsheetML document
/// </summary>
public class SpreadSheetTableAccessor
{
private static XNamespace ns;
private static XNamespace relationshipns;
/// <summary>
/// Static constructor
/// </summary>
static SpreadSheetTableAccessor()
{
ns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
relationshipns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
}
/// <summary>
/// Method for adding a new table definition part
/// </summary>
/// <param name="worksheet">Worksheet to add the table to</param>
/// <param name="tableStyle">Style to be assigned to the table</param>
/// <param name="useHeaders">Set a header row</param>
/// <param name="fromColumn">Initial column for table</param>
/// <param name="toColumn">Final column for table</param>
/// <param name="fromRow">Intial row for table</param>
/// <param name="toRow">Final row for table</param>
public static OpenXmlPowerToolsDocument Add(SmlDocument doc, string worksheetName, string tableStyle, bool useHeaders, short fromColumn, short toColumn, int fromRow, int toRow)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (SpreadsheetDocument document = streamDoc.GetSpreadsheetDocument())
{
//Getting the id for this table
int tableId = GetNextTableId(document);
//Set the table cell range
string tableRange = string.Format("{0}{1}:{2}{3}", WorksheetAccessor.GetColumnId(fromColumn),
fromRow,
WorksheetAccessor.GetColumnId(toColumn),
toRow);
//Creating a new id for the relationship between the table definition part and the worksheet
string tableRelationShipId = "rId" + Guid.NewGuid();
//Create a new table definition part
WorksheetPart worksheet = WorksheetAccessor.Get(document, worksheetName);
TableDefinitionPart table = worksheet.AddNewPart<TableDefinitionPart>(tableRelationShipId);
//string tableColumns = string.Empty;
XElement tableColumnsXElement = new XElement(ns + "tableColumns", new XAttribute("count", (toColumn - fromColumn) + 1));
//Get the name for table column elements from the first table row
string[] tableHeaders = GetTableHeaders(document, worksheet, fromRow, fromColumn, toColumn);
for (int i = 0; i <= (toColumn - fromColumn); i++)
{
//Create the markup for the SpreadsheetML table column elements
tableColumnsXElement.Add(
new XElement(ns + "tableColumn", new XAttribute("id", i + 1), new XAttribute("name", tableHeaders[i])));
}
XElement tableXElement =
new XElement(ns + "table",
new XAttribute("xmlns", ns), //default namespace
new XAttribute("id", tableId),
new XAttribute("name", "Table" + tableId.ToString()),
new XAttribute("displayName", "Table" + tableId.ToString()),
new XAttribute("ref", tableRange),
new XAttribute("totalsRowShown", "0"));
if (useHeaders)
{
tableXElement.Add(
new XElement(ns + "autoFilter", new XAttribute("ref", tableRange)));
}
tableXElement.Add(tableColumnsXElement);
tableXElement.Add(
new XElement(ns + "tableStyleInfo",
new XAttribute("name", tableStyle),
new XAttribute("showFirstColumn", "0"),
new XAttribute("showLastColumn", "0"),
new XAttribute("showRowStripes", "0"),
new XAttribute("showColumnStripes", "0")));
//Write the markup to the Table Definition Part Stream
XmlWriter tablePartStreamWriter = XmlWriter.Create(table.GetStream());
tableXElement.WriteTo(tablePartStreamWriter);
tablePartStreamWriter.Flush();
tablePartStreamWriter.Close();
//Create or modify the table parts definition at worksheet (for setting the relationship id with the new table)
XDocument worksheetMarkup = worksheet.GetXDocument();
//Look for the tableParts element at worksheet markup
XElement tablePartsElement = worksheetMarkup.Root.Element(ns + "tableParts");
if (tablePartsElement != null)
{
//tableParts elements does exist at worksheet markup
//increment the tableParts count attribute value
short tableCount = System.Convert.ToInt16(tablePartsElement.Attribute("count").Value);
tablePartsElement.SetAttributeValue("count", tableCount++.ToString());
}
else
{
//tableParts does not exist at worksheet markup
//create a new tableParts element
tablePartsElement = new XElement(ns + "tableParts",
new XAttribute(ns + "count", "1"));
worksheetMarkup.Root.Add(tablePartsElement);
}
//create the tablePart element
XElement tablePartEntryElement = new XElement(ns + "tablePart",
new XAttribute(relationshipns + "id", tableRelationShipId));
//add the new tablePart element to the worksheet tableParts element
tablePartsElement.Add(tablePartEntryElement);
worksheet.PutXDocument();
}
return streamDoc.GetModifiedDocument();
}
}
/// <summary>
/// Returns the id for the next table to add to the SpreadSheetML document
/// </summary>
/// <returns></returns>
private static int GetNextTableId(SpreadsheetDocument document)
{
int tableCount = 0;
foreach (WorksheetPart worksheet in document.WorkbookPart.WorksheetParts)
{ //Loop the worksheets to sum up the tables defined in each one
tableCount += worksheet.TableDefinitionParts.Count();
}
return ++tableCount;
}
/// <summary>
/// Get the values for the table header row (table initial row)
/// </summary>
/// <param name="worksheet">Worksheet where the table is being defined</param>
/// <param name="row">Table initial row</param>
/// <param name="fromColumn">Table initial column</param>
/// <param name="toColumn">Table final column</param>
/// <returns></returns>
private static string[] GetTableHeaders(SpreadsheetDocument document, WorksheetPart worksheet, int row, short fromColumn, short toColumn)
{
List<string> tableHeaders = new List<string>();
for (short c = fromColumn; c <= toColumn; c++)
{
tableHeaders.Add(WorksheetAccessor.GetValue(document, worksheet, c, row));
}
return tableHeaders.ToArray<string>();
}
}
}

View File

@@ -0,0 +1,216 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
/// <summary>
/// Manages SpreadsheetDocument content
/// </summary>
public class SpreadsheetDocumentManager
{
private static XNamespace ns;
private static XNamespace relationshipsns;
private static int headerRow = 1;
static SpreadsheetDocumentManager()
{
ns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
relationshipsns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
}
/// <summary>
/// Creates a spreadsheet document from a value table
/// </summary>
/// <param name="filePath">Path to store the document</param>
/// <param name="headerList">Contents of first row (header)</param>
/// <param name="valueTable">Contents of data</param>
/// <param name="initialRow">Row to start copying data from</param>
/// <returns></returns>
public static void Create(SpreadsheetDocument document, List<string> headerList, string[][] valueTable, int initialRow)
{
headerRow = initialRow;
//Creates a worksheet with given data
WorksheetPart worksheet = WorksheetAccessor.Create(document, headerList, valueTable, headerRow);
}
/// <summary>
/// Creates a spreadsheet document with a chart from a value table
/// </summary>
/// <param name="filePath">Path to store the document</param>
/// <param name="headerList">Contents of first row (header)</param>
/// <param name="valueTable">Contents of data</param>
/// <param name="chartType">Chart type</param>
/// <param name="categoryColumn">Column to use as category for charting</param>
/// <param name="columnsToChart">Columns to use as data series</param>
/// <param name="initialRow">Row index to start copying data</param>
/// <returns>SpreadsheetDocument</returns>
public static void Create(SpreadsheetDocument document, List<string> headerList, string[][] valueTable, ChartType chartType, string categoryColumn, List<string> columnsToChart, int initialRow)
{
headerRow = initialRow;
//Creates worksheet with data
WorksheetPart worksheet = WorksheetAccessor.Create(document, headerList, valueTable, headerRow);
//Creates chartsheet with given series and category
string sheetName = GetSheetName(worksheet, document);
ChartsheetPart chartsheet =
ChartsheetAccessor.Create(document,
chartType,
GetValueReferences(sheetName, categoryColumn, headerList, columnsToChart, valueTable),
GetHeaderReferences(sheetName, categoryColumn, headerList, columnsToChart, valueTable),
GetCategoryReference(sheetName, categoryColumn, headerList, valueTable)
);
}
/// <summary>
/// Gets the internal name of a worksheet from a document
/// </summary>
private static string GetSheetName(WorksheetPart worksheet, SpreadsheetDocument document)
{
//Gets the id of worksheet part
string partId = document.WorkbookPart.GetIdOfPart(worksheet);
XDocument workbookDocument = document.WorkbookPart.GetXDocument();
//Gets the name from sheet tag related to worksheet
string sheetName =
workbookDocument.Root
.Element(ns + "sheets")
.Elements(ns + "sheet")
.Where(
t =>
t.Attribute(relationshipsns + "id").Value == partId
).First()
.Attribute("name").Value;
return sheetName;
}
/// <summary>
/// Gets the range reference for category
/// </summary>
/// <param name="sheetName">worksheet to take data from</param>
/// <param name="headerColumn">name of column used as category</param>
/// <param name="headerList">column names from data</param>
/// <param name="valueTable">Data values</param>
/// <returns></returns>
private static string GetCategoryReference(string sheetName, string headerColumn, List<string> headerList, string[][] valueTable)
{
int categoryColumn = headerList.IndexOf(headerColumn.ToUpper()) + 1;
int numRows = valueTable.GetLength(0);
return GetRangeReference(
sheetName,
categoryColumn,
headerRow + 1,
categoryColumn,
numRows + headerRow
);
}
/// <summary>
/// Gets a list of range references for each of the series headers
/// </summary>
/// <param name="sheetName">worksheet to take data from</param>
/// <param name="headerColumn">name of column used as category</param>
/// <param name="headerList">column names from data</param>
/// <param name="valueTable">Data values</param>
/// <param name="colsToChart">Columns used as data series</param>
/// <returns></returns>
private static List<string> GetHeaderReferences(string sheetName, string headerColumn, List<string> headerList, List<string> colsToChart, string[][] valueTable)
{
List<string> valueReferenceList = new List<string>();
foreach (string column in colsToChart)
{
valueReferenceList.Add(
GetRangeReference(
sheetName,
headerList.IndexOf(column.ToUpper()) + 1,
headerRow
)
);
}
return valueReferenceList;
}
/// <summary>
/// Gets a list of range references for each of the series values
/// </summary>
/// <param name="sheetName">worksheet to take data from</param>
/// <param name="headerColumn">name of column used as category</param>
/// <param name="headerList">column names from data</param>
/// <param name="valueTable">Data values</param>
/// <param name="colsToChart">Columns used as data series</param>
/// <returns></returns>
private static List<string> GetValueReferences(string sheetName, string headerColumn, List<string> headerList, List<string> colsToChart, string[][] valueTable)
{
List<string> valueReferenceList = new List<string>();
int numRows = valueTable.GetLength(0);
foreach (string column in colsToChart)
{
int dataColumn = headerList.IndexOf(column.ToUpper()) + 1;
valueReferenceList.Add(
GetRangeReference(
sheetName,
dataColumn,
headerRow + 1,
dataColumn,
numRows + headerRow
)
);
}
return valueReferenceList;
}
/// <summary>
/// Gets a formatted representation of a cell range from a worksheet
/// </summary>
private static string GetRangeReference(string worksheet, int column, int row)
{
return string.Format("{0}!{1}{2}", worksheet, WorksheetAccessor.GetColumnId(column), row);
}
/// <summary>
/// Gets a formatted representation of a cell range from a worksheet
/// </summary>
private static string GetRangeReference(string worksheet, int startColumn, int startRow, int endColumn, int endRow)
{
return string.Format("{0}!{1}{2}:{3}{4}",
worksheet,
WorksheetAccessor.GetColumnId(startColumn),
startRow,
WorksheetAccessor.GetColumnId(endColumn),
endRow
);
}
/// <summary>
/// Creates an empty (base) workbook document
/// </summary>
/// <returns></returns>
private static XDocument CreateEmptyWorkbook()
{
XDocument document =
new XDocument(
new XElement(ns + "workbook",
new XAttribute("xmlns", ns),
new XAttribute(XNamespace.Xmlns + "r", relationshipsns),
new XElement(ns + "sheets")
)
);
return document;
}
}
}

View File

@@ -0,0 +1,459 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Xml;
using DocumentFormat.OpenXml.Packaging;
using System.Collections.ObjectModel;
using System;
namespace OpenXmlPowerTools
{
/// <summary>
/// Provides access to style operations
/// </summary>
public class StyleAccessor
{
//private XDocument xmlStylesDefinitionDocument;
private static XNamespace ns;
/// <summary>
/// newStyleNameSuffic variable
/// </summary>
public static readonly string newStyleNameSuffix = "_1";
static StyleAccessor()
{
ns = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
}
public static void CreateIndexStyles(WordprocessingDocument document, string stylesSourceFile, bool addDefaultStyles)
{
if (stylesSourceFile == "")
{
if (addDefaultStyles)
{
XElement Index1 = new XElement(ns + "style",
new XAttribute(ns + "type", "paragraph"),
new XAttribute(ns + "styleId", "Index1"),
new XElement(ns + "name",
new XAttribute(ns + "val", "index 1")),
new XElement(ns + "basedOn",
new XAttribute(ns + "val", "Normal")),
new XElement(ns + "next",
new XAttribute(ns + "val", "Normal")),
new XElement(ns + "autoRedefine"),
new XElement(ns + "semiHidden"),
new XElement(ns + "unhideWhenUsed"),
new XElement(ns + "pPr",
new XElement(ns + "spacing",
new XAttribute(ns + "after", "0"),
new XAttribute(ns + "line", "240"),
new XAttribute(ns + "lineRule", "auto")),
new XElement(ns + "ind",
new XAttribute(ns + "left", "220"),
new XAttribute(ns + "hanging", "220"))));
AddStyleDefinition(document, Index1);
}
}
else
{
// add the styles from the styles source file
XDocument StyleXmlPart = GetStylesDocument(document);
// the preffix must be empty, because the styles need to be recognized by the TOC
XDocument stylesSource = XDocument.Load(stylesSourceFile);
IEnumerable<XElement> IndexStyles = GetStyleHierarchy("Index1", stylesSource, string.Empty);
AddStyleDefinition(document, IndexStyles);
}
document.MainDocumentPart.StyleDefinitionsPart.PutXDocument();
}
public static void CreateTOAStyles(WordprocessingDocument document, string stylesSourceFile, bool addDefaultStyles)
{
if (stylesSourceFile == "")
{
if (addDefaultStyles)
{
XElement TOAHeading = new XElement(ns + "style",
new XAttribute(ns + "type", "paragraph"),
new XAttribute(ns + "styleId", "TOAHeading"),
new XElement(ns + "name",
new XAttribute(ns + "val", "toa heading")),
new XElement(ns + "basedOn",
new XAttribute(ns + "val", "Normal")),
new XElement(ns + "next",
new XAttribute(ns + "val", "Normal")),
new XElement(ns + "semiHidden"),
new XElement(ns + "unhideWhenUsed"),
new XElement(ns + "pPr",
new XElement(ns + "spacing",
new XAttribute(ns + "before", "120"))),
new XElement(ns + "rPr",
new XElement(ns + "b"),
new XElement(ns + "bCs"),
new XElement(ns + "sz",
new XAttribute(ns + "val", 24)),
new XElement(ns + "szCs",
new XAttribute(ns + "val", 24))));
AddStyleDefinition(document, TOAHeading);
XElement tableOfAuthorities = new XElement(ns + "style",
new XAttribute(ns + "type", "paragraph"),
new XAttribute(ns + "styleId", "TableofAuthorities"),
new XElement(ns + "name",
new XAttribute(ns + "val", "table of authorities")),
new XElement(ns + "basedOn",
new XAttribute(ns + "val", "Normal")),
new XElement(ns + "next",
new XAttribute(ns + "val", "Normal")),
new XElement(ns + "semiHidden"),
new XElement(ns + "unhideWhenUsed"),
new XElement(ns + "pPr",
new XElement(ns + "spacing",
new XAttribute(ns + "after", "0")),
new XElement(ns + "ind",
new XAttribute(ns + "left", "220"),
new XAttribute(ns + "hanging", "220"))));
AddStyleDefinition(document, tableOfAuthorities);
}
}
else
{
// add the styles from the styles source file
XDocument StyleXmlPart = GetStylesDocument(document);
// the prefix must be empty, because the styles need to be recognized by the TOC
XDocument stylesSource = XDocument.Load(stylesSourceFile);
IEnumerable<XElement> TOAStyles = GetStyleHierarchy("TOAHeading", stylesSource, string.Empty);
TOAStyles = TOAStyles.Concat(GetStyleHierarchy("TableofAuthorities", stylesSource, string.Empty));
AddStyleDefinition(document, TOAStyles);
}
document.MainDocumentPart.StyleDefinitionsPart.PutXDocument();
}
private static XDocument GetStylesDocument(WordprocessingDocument document)
{
if (document.MainDocumentPart.StyleDefinitionsPart != null)
return document.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
return null;
}
public static XDocument GetStylesDocument(WmlDocument doc)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
return GetStylesDocument(document);
}
}
/// <summary>
/// Gets the style hierarchy (link styles, next styles and basedOn styles) associated
/// to the specified style, in a XElement collection
/// </summary>
/// <param name="styleName">Name of the style from where to get the hierarchy</param>
/// <param name="stylesFile">File from where styles are taken </param>
/// <param name="styleNameSuffix">Suffix of style name.</param>
/// <returns>a collection containing the specified style and all the styles associated with it</returns>
private static Collection<XElement> GetStyleHierarchy(string styleName, XDocument stylesFile, string styleNameSuffix)
{
try
{
Collection<XElement> stylesCollection = new Collection<XElement>();
GetStyleHierarchyProcess(styleName, stylesFile, stylesCollection);
return stylesCollection;
}
catch (XmlException ex)
{
throw new ArgumentException("File specified is not a valid XML file", ex);
}
}
/// <summary>
/// Gets the xml of a specific style definition
/// </summary>
/// <param name="styleName">Name of the style to get from the styles file</param>
/// <param name="xmlStyleDefinitions">Style definitions</param>
/// <param name="stylesCollection">Collection of styles</param>
private static void GetStyleHierarchyProcess(string styleName, XDocument xmlStyleDefinitions, Collection<XElement> stylesCollection)
{
XName style = ns + "style";
XName styleId = ns + "styleId";
// the style name can come empty, because the given style could not have a link, basedOn or next style.
// In those cases the stylename will come empty
if (styleName != "")
{
// Creates a copy of the xmlStyleDefinition variable so the original xml will not be altered
XElement actualStyle = new XElement(xmlStyleDefinitions.Root);
actualStyle = actualStyle.Descendants().Where
(
tag =>
(tag.Name == style) && (tag.Attribute(styleId).Value.ToUpper() == styleName.ToUpper())
).ToList().FirstOrDefault();
if (actualStyle != null)
{
// Looks in the stylesCollection if the style has already been added
IEnumerable<XElement> insertedStyles =
stylesCollection.Where
(
tag =>
(tag.Name == style) && (tag.Attribute(styleId).Value.ToUpper() == styleName.ToUpper())
);
// If the style has not been inserted
if (insertedStyles.Count() == 0)
{
stylesCollection.Add(actualStyle);
GetStyleHierarchyProcess(GetLinkStyleId(actualStyle), xmlStyleDefinitions, stylesCollection);
GetStyleHierarchyProcess(GetNextStyleId(actualStyle), xmlStyleDefinitions, stylesCollection);
GetStyleHierarchyProcess(GetBasedOnStyleId(actualStyle), xmlStyleDefinitions, stylesCollection);
}
// Changes the name of the style, so there would be no conflict with the original styles definition
actualStyle.Attribute(styleId).Value = actualStyle.Attribute(styleId).Value + newStyleNameSuffix;
}
else
throw new InvalidOperationException("Style or dependencies not found in the given style library.");
}
}
/// <summary>
/// Gets the name of the 'link' style associated to the given style
/// </summary>
/// <param name="xmlStyle">Xml to search for linked style</param>
/// <returns>Name of the style</returns>
private static string GetLinkStyleId(XElement xmlStyle)
{
XName val = ns + "val";
string linkStyleId = "";
XElement linkStyle = xmlStyle.Descendants(ns + "link").FirstOrDefault();
if (linkStyle != null)
{
linkStyleId = linkStyle.Attribute(val).Value;
// Changes the name of the attribute, because the new added style is being renamed
linkStyle.Attribute(val).Value = linkStyle.Attribute(val).Value + newStyleNameSuffix;
}
return linkStyleId;
}
/// <summary>
/// Gets the name of the style tagged as 'next' associated to a given style
/// </summary>
/// <param name="xmlStyle">Xml to search for next style</param>
/// <returns>Name of the style</returns>
private static string GetNextStyleId(XElement xmlStyle)
{
XName val = ns + "val";
string nextStyleId = "";
XElement nextStyle = xmlStyle.Descendants(ns + "next").FirstOrDefault();
if (nextStyle != null)
{
nextStyleId = nextStyle.Attribute(val).Value;
// Changes the name of the attribute, because the new added style is being renamed
nextStyle.Attribute(val).Value = nextStyle.Attribute(val).Value + newStyleNameSuffix;
}
return nextStyleId;
}
/// <summary>
/// Gets the name of the style tagged as 'basedOn' associated to a given style
/// </summary>
/// <param name="xmlStyle">Xml to search for basedOn style</param>
/// <returns>Name of the style</returns>
private static string GetBasedOnStyleId(XElement xmlStyle)
{
XName val = ns + "val";
string basedOnStyleId = "";
XElement basedOnStyle = xmlStyle.Descendants(ns + "basedOn").FirstOrDefault();
if (basedOnStyle != null)
{
basedOnStyleId = basedOnStyle.Attribute(val).Value;
// Change the name of the attribute, because the new added style is being renamed
basedOnStyle.Attribute(val).Value = basedOnStyle.Attribute(val).Value + newStyleNameSuffix;
}
return basedOnStyleId;
}
/// <summary>
/// Sets a new styles part inside the document
/// </summary>
/// <param name="newStylesDocument">Path of styles definition file</param>
public static OpenXmlPowerToolsDocument SetStylePart(WmlDocument doc, XDocument newStylesDocument)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
// Replaces XDocument with the style file to transfer
if (document.MainDocumentPart.StyleDefinitionsPart == null)
document.MainDocumentPart.AddNewPart<StyleDefinitionsPart>();
document.MainDocumentPart.StyleDefinitionsPart.PutXDocument(newStylesDocument);
}
return streamDoc.GetModifiedDocument();
}
}
/// <summary>
/// Adds a new style definition
/// </summary>
/// <param name="xmlStyleDefinition">Style definition</param>
public static void AddStyleDefinition(WordprocessingDocument document, XElement xmlStyleDefinition)
{
// Inserts the new style
XDocument stylesPart = GetStylesDocument(document);
stylesPart.Root.Add(xmlStyleDefinition);
}
/// <summary>
/// Adds a set of styles in the styles.xml file
/// </summary>
/// <param name="xmlStyleDefinitions">Collection of style definitions</param>
public static void AddStyleDefinition(WordprocessingDocument document, IEnumerable<XElement> xmlStyleDefinitions)
{
XDocument stylesPart = GetStylesDocument(document);
foreach (XElement xmlStyleDefinition in xmlStyleDefinitions)
{
stylesPart.Root.Add(xmlStyleDefinition);
}
}
/// <summary>
/// Insert a style into a given xmlpath inside the document part
/// </summary>
/// <param name="xpathInsertionPoint">place where we are going to put the style</param>
/// <param name="styleValue">name of the style</param>
/// <param name="stylesSource">XDocument containing styles</param>
public static OpenXmlPowerToolsDocument Insert(WmlDocument doc, string xpathInsertionPoint, string styleValue, XDocument stylesSource)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
XDocument xDocument = document.MainDocumentPart.GetXDocument();
XmlDocument xmlMainDocument = new XmlDocument();
xmlMainDocument.Load(xDocument.CreateReader());
// create the style element to add in the document, based upon the style name.
// this is an example of an style element
// <w:pStyle w:val="Heading1" />
// so, in order to construct this, we have to know already if the style will be placed inside
// a run or inside a paragraph. to know this we have to verify against the xpath, and know if
// the query want to access a 'run' or a paragraph
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(xmlMainDocument.NameTable);
namespaceManager.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
XmlNodeList insertionPoints = xmlMainDocument.SelectNodes(xpathInsertionPoint, namespaceManager);
if (insertionPoints.Count == 0)
throw new ArgumentException("The xpath query did not return a valid location.");
foreach (XmlNode insertionPoint in insertionPoints)
{
XmlElement xmlStyle = null;
if (insertionPoint.LocalName == "r" || insertionPoint.LocalName == "p")
{
XmlNode propertiesElement = insertionPoint.SelectSingleNode(@"w:pPr|w:rPr", namespaceManager);
//if (propertiesElement != null)
//{
if (insertionPoint.Name == "w:p")
{
xmlStyle = xmlMainDocument.CreateElement("w", "pStyle", namespaceManager.LookupNamespace("w"));
// retrieve the suffix from the styleAccesor class
xmlStyle.SetAttribute("val", namespaceManager.LookupNamespace("w"), styleValue + newStyleNameSuffix);
// check if the rPr or pPr element exist, if so, then add the style xml element
// inside, if not, then add a new rPr or pPr element
if (propertiesElement != null)
{
// check if there is already a style node and remove it
XmlNodeList xmlStyleList = propertiesElement.SelectNodes("w:pStyle", namespaceManager);
for (int i = 0; i < xmlStyleList.Count; i++)
{
propertiesElement.RemoveChild(xmlStyleList[i]);
}
propertiesElement.PrependChild(xmlStyle);
}
else
{
propertiesElement = xmlMainDocument.CreateElement("w", "pPr", namespaceManager.LookupNamespace("w"));
propertiesElement.PrependChild(xmlStyle);
insertionPoint.PrependChild(propertiesElement);
}
}
if (insertionPoint.Name == "w:r")
{
xmlStyle = xmlMainDocument.CreateElement("w", "rStyle", namespaceManager.LookupNamespace("w"));
xmlStyle.SetAttribute("val", namespaceManager.LookupNamespace("w"), styleValue + newStyleNameSuffix);
if (propertiesElement != null)
{
// check if there is already a style node and remove it
XmlNodeList xmlStyleList = propertiesElement.SelectNodes("w:rStyle", namespaceManager);
for (int i = 0; i < xmlStyleList.Count; i++)
{
propertiesElement.RemoveChild(xmlStyleList[i]);
}
propertiesElement.PrependChild(xmlStyle);
}
else
{
propertiesElement = xmlMainDocument.CreateElement("w", "rPr", namespaceManager.LookupNamespace("w"));
propertiesElement.PrependChild(xmlStyle);
insertionPoint.PrependChild(propertiesElement);
}
}
//}
}
else
{
throw new ArgumentException("The xpath query did not return a valid location.");
}
XDocument xNewDocument = new XDocument();
using (XmlWriter xWriter = xNewDocument.CreateWriter())
xmlMainDocument.WriteTo(xWriter);
document.MainDocumentPart.PutXDocument(xNewDocument);
// the style has been added in the main document part, but now we have to add the
// style definition in the styles definitions part. the style definition need to be
// extracted from the given inputStyle file.
// Because a style can be linked with other styles and
// can also be based on other styles, all the complete hierarchy of styles has
// to be added
Collection<XElement> styleHierarchy = StyleAccessor.GetStyleHierarchy(styleValue, stylesSource, newStyleNameSuffix);
// open the styles file in the document
XDocument xmlStylesDefinitionDocument = StyleAccessor.GetStylesDocument(document);
XDocument xElem = new XDocument();
xElem.Add(xmlStylesDefinitionDocument.Root);
//insert the new style
foreach (XElement xmlStyleDefinition in styleHierarchy)
{
xElem.Root.Add(xmlStyleDefinition);
}
document.MainDocumentPart.StyleDefinitionsPart.PutXDocument(xElem);
}
}
return streamDoc.GetModifiedDocument();
}
}
}
}

View File

@@ -0,0 +1,425 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
public partial class WmlDocument : OpenXmlPowerToolsDocument
{
public WmlDocument SearchAndReplace(string search, string replace, bool matchCase)
{
return TextReplacer.SearchAndReplace(this, search, replace, matchCase);
}
}
public partial class PmlDocument : OpenXmlPowerToolsDocument
{
public PmlDocument SearchAndReplace(string search, string replace, bool matchCase)
{
return TextReplacer.SearchAndReplace(this, search, replace, matchCase);
}
}
public class TextReplacer
{
private class MatchSemaphore
{
public int MatchId;
public MatchSemaphore(int matchId)
{
MatchId = matchId;
}
}
private static XObject CloneWithAnnotation(XNode node)
{
XElement element = node as XElement;
if (element != null)
{
XElement newElement = new XElement(element.Name,
element.Attributes(),
element.Nodes().Select(n => CloneWithAnnotation(n)));
if (element.Annotation<MatchSemaphore>() != null)
newElement.AddAnnotation(element.Annotation<MatchSemaphore>());
}
return node;
}
private static object WmlSearchAndReplaceTransform(XNode node,
string search, string replace, bool matchCase)
{
XElement element = node as XElement;
if (element != null)
{
if (element.Name == W.p)
{
string contents = element.Descendants(W.t).Select(t => (string)t).StringConcatenate();
if (contents.Contains(search) ||
(!matchCase && contents.ToUpper().Contains(search.ToUpper())))
{
XElement paragraphWithSplitRuns = new XElement(W.p,
element.Attributes(),
element.Nodes().Select(n => WmlSearchAndReplaceTransform(n, search,
replace, matchCase)));
XElement[] subRunArray = paragraphWithSplitRuns
.Elements(W.r)
.Where(e => {
XElement subRunElement = e.Elements().FirstOrDefault(el => el.Name != W.rPr);
if (subRunElement == null)
return false;
return W.SubRunLevelContent.Contains(subRunElement.Name);
})
.ToArray();
int paragraphChildrenCount = subRunArray.Length;
int matchId = 1;
foreach (var pc in subRunArray
.Take(paragraphChildrenCount - (search.Length - 1))
.Select((c, i) => new { Child = c, Index = i, }))
{
var subSequence = subRunArray.SequenceAt(pc.Index).Take(search.Length);
var zipped = subSequence.Zip(search, (pcp, c) => new
{
ParagraphChildProjection = pcp,
CharacterToCompare = c,
});
bool dontMatch = zipped.Any(z => {
if (z.ParagraphChildProjection.Annotation<MatchSemaphore>() != null)
return true;
bool b;
if (matchCase)
b = z.ParagraphChildProjection.Value != z.CharacterToCompare.ToString();
else
b = z.ParagraphChildProjection.Value.ToUpper() != z.CharacterToCompare.ToString().ToUpper();
return b;
});
bool match = !dontMatch;
if (match)
{
foreach (var item in subSequence)
item.AddAnnotation(new MatchSemaphore(matchId));
++matchId;
}
}
// The following code is locally impure, as this is the most expressive way to write it.
XElement paragraphWithReplacedRuns = (XElement)CloneWithAnnotation(paragraphWithSplitRuns);
for (int id = 1; id < matchId; ++id)
{
List<XElement> elementsToReplace = paragraphWithReplacedRuns
.Elements()
.Where(e => {
var sem = e.Annotation<MatchSemaphore>();
if (sem == null)
return false;
return sem.MatchId == id;
})
.ToList();
elementsToReplace.First().AddBeforeSelf(
new XElement(W.r,
elementsToReplace.First().Elements(W.rPr),
new XElement(W.t, replace)));
elementsToReplace.Remove();
}
var groupedAdjacentRunsWithIdenticalFormatting =
paragraphWithReplacedRuns
.Elements()
.GroupAdjacent(ce =>
{
if (ce.Name != W.r)
return "DontConsolidate";
if (ce.Elements().Where(e => e.Name != W.rPr).Count() != 1 ||
ce.Element(W.t) == null)
return "DontConsolidate";
if (ce.Element(W.rPr) == null)
return "";
return ce.Element(W.rPr).ToString(SaveOptions.None);
});
XElement paragraphWithConsolidatedRuns = new XElement(W.p,
groupedAdjacentRunsWithIdenticalFormatting.Select(g =>
{
if (g.Key == "DontConsolidate")
return (object)g;
string textValue = g.Select(r => r.Element(W.t).Value).StringConcatenate();
XAttribute xs = null;
if (textValue[0] == ' ' || textValue[textValue.Length - 1] == ' ')
xs = new XAttribute(XNamespace.Xml + "space", "preserve");
return new XElement(W.r,
g.First().Elements(W.rPr),
new XElement(W.t, xs, textValue));
}));
return paragraphWithConsolidatedRuns;
}
return element;
}
if (element.Name == W.r && element.Elements(W.t).Any())
{
var collectionOfRuns = element.Elements()
.Where(e => e.Name != W.rPr)
.Select(e =>
{
if (e.Name == W.t)
{
string s = (string)e;
IEnumerable<XElement> collectionOfSubRuns = s.Select(c =>
{
XElement newRun = new XElement(W.r,
element.Elements(W.rPr),
new XElement(W.t,
c == ' ' ?
new XAttribute(XNamespace.Xml + "space", "preserve") :
null, c));
return newRun;
});
return (object)collectionOfSubRuns;
}
else
{
XElement newRun = new XElement(W.r,
element.Elements(W.rPr),
e);
return newRun;
}
});
return collectionOfRuns;
}
return new XElement(element.Name,
element.Attributes(),
element.Nodes().Select(n => WmlSearchAndReplaceTransform(n,
search, replace, matchCase)));
}
return node;
}
private static void WmlSearchAndReplaceInXDocument(XDocument xDocument, string search,
string replace, bool matchCase)
{
XElement newRoot = (XElement)WmlSearchAndReplaceTransform(xDocument.Root,
search, replace, matchCase);
xDocument.Elements().First().ReplaceWith(newRoot);
}
public static WmlDocument SearchAndReplace(WmlDocument doc, string search, string replace, bool matchCase)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
SearchAndReplace(document, search, replace, matchCase);
}
return streamDoc.GetModifiedWmlDocument();
}
}
public static void SearchAndReplace(WordprocessingDocument wordDoc, string search,
string replace, bool matchCase)
{
if (RevisionAccepter.HasTrackedRevisions(wordDoc))
throw new InvalidDataException(
"Search and replace will not work with documents " +
"that contain revision tracking.");
XDocument xDoc;
xDoc = wordDoc.MainDocumentPart.DocumentSettingsPart.GetXDocument();
if (xDoc.Descendants(W.trackRevisions).Any())
throw new InvalidDataException("Revision tracking is turned on for document.");
xDoc = wordDoc.MainDocumentPart.GetXDocument();
WmlSearchAndReplaceInXDocument(xDoc, search, replace, matchCase);
wordDoc.MainDocumentPart.PutXDocument();
foreach (var part in wordDoc.MainDocumentPart.HeaderParts)
{
xDoc = part.GetXDocument();
WmlSearchAndReplaceInXDocument(xDoc, search, replace, matchCase);
part.PutXDocument();
}
foreach (var part in wordDoc.MainDocumentPart.FooterParts)
{
xDoc = part.GetXDocument();
WmlSearchAndReplaceInXDocument(xDoc, search, replace, matchCase);
part.PutXDocument();
}
if (wordDoc.MainDocumentPart.EndnotesPart != null)
{
xDoc = wordDoc.MainDocumentPart.EndnotesPart.GetXDocument();
WmlSearchAndReplaceInXDocument(xDoc, search, replace, matchCase);
wordDoc.MainDocumentPart.EndnotesPart.PutXDocument();
}
if (wordDoc.MainDocumentPart.FootnotesPart != null)
{
xDoc = wordDoc.MainDocumentPart.FootnotesPart.GetXDocument();
WmlSearchAndReplaceInXDocument(xDoc, search, replace, matchCase);
wordDoc.MainDocumentPart.FootnotesPart.PutXDocument();
}
}
private static object PmlReplaceTextTransform(XNode node, string search, string replace,
bool matchCase)
{
XElement element = node as XElement;
if (element != null)
{
if (element.Name == A.p)
{
string contents = element.Descendants(A.t).Select(t => (string)t).StringConcatenate();
if (contents.Contains(search) ||
(!matchCase && contents.ToUpper().Contains(search.ToUpper())))
{
XElement paragraphWithSplitRuns = new XElement(A.p,
element.Attributes(),
element.Nodes().Select(n => PmlReplaceTextTransform(n, search,
replace, matchCase)));
XElement[] subRunArray = paragraphWithSplitRuns
.Elements(A.r)
.Where(e =>
{
XElement subRunElement = e.Elements().FirstOrDefault(el => el.Name != A.rPr);
if (subRunElement == null)
return false;
return subRunElement.Name == A.t;
})
.ToArray();
int paragraphChildrenCount = subRunArray.Length;
int matchId = 1;
foreach (var pc in subRunArray
.Take(paragraphChildrenCount - (search.Length - 1))
.Select((c, i) => new { Child = c, Index = i, }))
{
var subSequence = subRunArray.SequenceAt(pc.Index).Take(search.Length);
var zipped = subSequence.Zip(search, (pcp, c) => new
{
ParagraphChildProjection = pcp,
CharacterToCompare = c,
});
bool dontMatch = zipped.Any(z =>
{
if (z.ParagraphChildProjection.Annotation<MatchSemaphore>() != null)
return true;
bool b;
if (matchCase)
b = z.ParagraphChildProjection.Value != z.CharacterToCompare.ToString();
else
b = z.ParagraphChildProjection.Value.ToUpper() != z.CharacterToCompare.ToString().ToUpper();
return b;
});
bool match = !dontMatch;
if (match)
{
foreach (var item in subSequence)
item.AddAnnotation(new MatchSemaphore(matchId));
++matchId;
}
}
// The following code is locally impure, as this is the most expressive way to write it.
XElement paragraphWithReplacedRuns = (XElement)CloneWithAnnotation(paragraphWithSplitRuns);
for (int id = 1; id < matchId; ++id)
{
List<XElement> elementsToReplace = paragraphWithReplacedRuns
.Elements()
.Where(e =>
{
var sem = e.Annotation<MatchSemaphore>();
if (sem == null)
return false;
return sem.MatchId == id;
})
.ToList();
elementsToReplace.First().AddBeforeSelf(
new XElement(A.r,
elementsToReplace.First().Elements(A.rPr),
new XElement(A.t, replace)));
elementsToReplace.Remove();
}
var groupedAdjacentRunsWithIdenticalFormatting =
paragraphWithReplacedRuns
.Elements()
.GroupAdjacent(ce =>
{
if (ce.Name != A.r)
return "DontConsolidate";
if (ce.Elements().Where(e => e.Name != A.rPr).Count() != 1 ||
ce.Element(A.t) == null)
return "DontConsolidate";
if (ce.Element(A.rPr) == null)
return "";
return ce.Element(A.rPr).ToString(SaveOptions.None);
});
XElement paragraphWithConsolidatedRuns = new XElement(A.p,
groupedAdjacentRunsWithIdenticalFormatting.Select(g =>
{
if (g.Key == "DontConsolidate")
return (object)g;
string textValue = g.Select(r => r.Element(A.t).Value).StringConcatenate();
return new XElement(A.r,
g.First().Elements(A.rPr),
new XElement(A.t, textValue));
}));
return paragraphWithConsolidatedRuns;
}
}
if (element.Name == A.r && element.Elements(A.t).Any())
{
var collectionOfRuns = element.Elements()
.Where(e => e.Name != A.rPr)
.Select(e =>
{
if (e.Name == A.t)
{
string s = (string)e;
IEnumerable<XElement> collectionOfSubRuns = s.Select(c =>
{
XElement newRun = new XElement(A.r,
element.Elements(A.rPr),
new XElement(A.t, c));
return newRun;
});
return (object)collectionOfSubRuns;
}
else
{
XElement newRun = new XElement(A.r,
element.Elements(A.rPr),
e);
return newRun;
}
});
return collectionOfRuns;
}
return new XElement(element.Name,
element.Attributes(),
element.Nodes().Select(n => PmlReplaceTextTransform(n, search, replace, matchCase)));
}
return node;
}
public static PmlDocument SearchAndReplace(PmlDocument doc, string search, string replace, bool matchCase)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (PresentationDocument document = streamDoc.GetPresentationDocument())
{
SearchAndReplace(document, search, replace, matchCase);
}
return streamDoc.GetModifiedPmlDocument();
}
}
public static void SearchAndReplace(PresentationDocument pDoc, string search,
string replace, bool matchCase)
{
PresentationPart presentationPart = pDoc.PresentationPart;
foreach (var slidePart in presentationPart.SlideParts)
{
XDocument slideXDoc = slidePart.GetXDocument();
XElement root = slideXDoc.Root;
XElement newRoot = (XElement)PmlReplaceTextTransform(root, search, replace, matchCase);
slidePart.PutXDocument(new XDocument(newRoot));
}
}
}
}

View File

@@ -0,0 +1,214 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.IO;
using System.Linq;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
using System.IO.Packaging;
using System;
using System.Xml;
namespace OpenXmlPowerTools
{
/// <summary>
/// Provides access to theme operations
/// </summary>
public class ThemeAccessor
{
private static XNamespace ns;
private static XNamespace drawingns;
private static XNamespace relationshipns;
private static string mainDocumentRelationshipType;
private static string themeRelationshipType;
static ThemeAccessor()
{
ns = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
drawingns = "http://schemas.openxmlformats.org/drawingml/2006/main";
relationshipns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
mainDocumentRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
themeRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
}
/// <summary>
/// Gets the document theme
/// </summary>
public static OpenXmlPowerToolsDocument GetTheme(WmlDocument doc)
{
using (OpenXmlMemoryStreamDocument sourceStreamDoc = new OpenXmlMemoryStreamDocument(doc))
using (WordprocessingDocument document = sourceStreamDoc.GetWordprocessingDocument())
{
// Loads the theme part main file
ThemePart theme = document.MainDocumentPart.ThemePart;
if (theme != null)
{
XDocument themeDocument = theme.GetXDocument();
// Creates the theme package (thmx file)
using (OpenXmlMemoryStreamDocument streamDoc = OpenXmlMemoryStreamDocument.CreatePackage())
{
using (Package themePackage = streamDoc.GetPackage())
{
// Creates the theme manager part on the new package and loads default content
PackagePart newThemeManagerPart = themePackage.CreatePart(new Uri("/theme/theme/themeManager.xml", UriKind.RelativeOrAbsolute), "application/vnd.openxmlformats-officedocument.themeManager+xml");
themePackage.CreateRelationship(newThemeManagerPart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument");
using (XmlWriter xWriter = XmlWriter.Create(newThemeManagerPart.GetStream(FileMode.Create, FileAccess.Write)))
{
CreateEmptyThemeManager().WriteTo(xWriter);
xWriter.Flush();
}
// Creates the main theme part
PackagePart newThemePart = themePackage.CreatePart(new Uri("/theme/theme/" + theme.Uri.OriginalString.Substring(theme.Uri.OriginalString.LastIndexOf('/') + 1), UriKind.RelativeOrAbsolute), theme.ContentType);
newThemeManagerPart.CreateRelationship(newThemePart.Uri, TargetMode.Internal, theme.RelationshipType);
// Gets embeded part references
var embeddedItems =
themeDocument
.Descendants()
.Attributes(relationshipns + "embed");
foreach (IdPartPair partId in theme.Parts)
{
OpenXmlPart part = partId.OpenXmlPart;
// Creates the new media part inside the destination package
PackagePart newPart = themePackage.CreatePart(new Uri("/theme/media/" + part.Uri.OriginalString.Substring(part.Uri.OriginalString.LastIndexOf('/') + 1), UriKind.RelativeOrAbsolute), part.ContentType);
PackageRelationship relationship =
newThemePart.CreateRelationship(newPart.Uri, TargetMode.Internal, part.RelationshipType);
// Copies binary content from original part to destination part
Stream partStream = part.GetStream(FileMode.Open, FileAccess.Read);
Stream newPartStream = newPart.GetStream(FileMode.Create, FileAccess.Write);
byte[] fileContent = new byte[partStream.Length];
partStream.Read(fileContent, 0, (int)partStream.Length);
newPartStream.Write(fileContent, 0, (int)partStream.Length);
newPartStream.Flush();
// Replaces old embed part reference with the freshly created one
XAttribute relationshipAttribute = embeddedItems.FirstOrDefault(e => e.Value == theme.GetIdOfPart(part));
if (relationshipAttribute != null)
relationshipAttribute.Value = relationship.Id;
}
// Writes the updated theme XDocument into the destination package
using (XmlWriter newThemeWriter = XmlWriter.Create(newThemePart.GetStream(FileMode.Create, FileAccess.Write)))
themeDocument.WriteTo(newThemeWriter);
}
return streamDoc.GetModifiedDocument();
}
}
return null;
}
}
/// <summary>
/// Creates an empty theme manager document
/// </summary>
private static XDocument CreateEmptyThemeManager() {
return new XDocument(
new XElement(drawingns+"themeManager",
new XAttribute(XNamespace.Xmlns + "a", drawingns)
)
);
}
/// <summary>
/// Sets the document theme
/// </summary>
/// <param name="theme">Theme package</param>
public static OpenXmlPowerToolsDocument SetTheme(WmlDocument doc, OpenXmlPowerToolsDocument themeDoc)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
using (OpenXmlMemoryStreamDocument themeStream = new OpenXmlMemoryStreamDocument(themeDoc))
using (Package theme = themeStream.GetPackage())
{
// Gets the theme manager part
PackageRelationship themeManagerRelationship =
theme.GetRelationshipsByType(mainDocumentRelationshipType).FirstOrDefault();
if (themeManagerRelationship != null)
{
PackagePart themeManagerPart = theme.GetPart(themeManagerRelationship.TargetUri);
// Gets the theme main part
PackageRelationship themeRelationship =
themeManagerPart.GetRelationshipsByType(themeRelationshipType).FirstOrDefault();
if (themeRelationship != null)
{
PackagePart themePart = theme.GetPart(themeRelationship.TargetUri);
XDocument newThemeDocument = XDocument.Load(XmlReader.Create(themePart.GetStream(FileMode.Open, FileAccess.Read)));
// Removes existing theme part from document
if (document.MainDocumentPart.ThemePart != null)
document.MainDocumentPart.DeletePart(document.MainDocumentPart.ThemePart);
// Creates a new theme part
ThemePart documentThemePart = document.MainDocumentPart.AddNewPart<ThemePart>();
var embeddedItems =
newThemeDocument
.Descendants()
.Attributes(relationshipns + "embed");
foreach (PackageRelationship imageRelationship in themePart.GetRelationships())
{
// Adds an image part to the theme part and stores contents inside
PackagePart imagePart = theme.GetPart(imageRelationship.TargetUri);
ImagePart newImagePart =
documentThemePart.AddImagePart(GetImagePartType(imagePart.ContentType));
newImagePart.FeedData(imagePart.GetStream(FileMode.Open, FileAccess.Read));
// Updates relationship references into the theme XDocument
XAttribute relationshipAttribute = embeddedItems.FirstOrDefault(e => e.Value == imageRelationship.Id);
if (relationshipAttribute != null)
relationshipAttribute.Value = documentThemePart.GetIdOfPart(newImagePart);
}
documentThemePart.PutXDocument(newThemeDocument);
}
}
}
}
return streamDoc.GetModifiedDocument();
}
}
/// <summary>
/// Gets the image type representation for a mimetype
/// </summary>
/// <param name="imageContentType">Content mimetype</param>
/// <returns>Image type</returns>
private static ImagePartType GetImagePartType(string imageContentType)
{
switch (imageContentType) {
case "image/jpeg":
return ImagePartType.Jpeg;
case "image/emf":
return ImagePartType.Emf;
case "image/gif":
return ImagePartType.Gif;
case "image/ico":
return ImagePartType.Icon;
case "image/pcx":
return ImagePartType.Pcx;
case "image/png":
return ImagePartType.Png;
case "image/tiff":
return ImagePartType.Tiff;
case "image/wmf":
return ImagePartType.Wmf;
default:
return ImagePartType.Bmp;
}
}
}
}

View File

@@ -0,0 +1,247 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools
{
/// <summary>
/// Provides access to watermark operations
/// </summary>
public class WatermarkAccessor
{
private static XNamespace ns;
private static XNamespace officens;
private static XNamespace vmlns;
private static XNamespace relationshipsns;
private static string diagonalWatermarkStyle = "position:absolute;margin-left:0;margin-top:0;width:527.85pt;height:131.95pt;rotation:315;z-index:-251656192;mso-position-horizontal:center;mso-position-horizontal-relative:margin;mso-position-vertical:center;mso-position-vertical-relative:margin";
private static string defaultWatermarkStyle = "position:absolute;margin-left:0;margin-top:0;width:468pt;height:117pt;z-index:-251652096;mso-position-horizontal:center;mso-position-horizontal-relative:margin;mso-position-vertical:center;mso-position-vertical-relative:margin";
static WatermarkAccessor()
{
ns = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
officens = "urn:schemas-microsoft-com:office:office";
vmlns = "urn:schemas-microsoft-com:vml";
relationshipsns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
}
/// <summary>
/// Inserts a watermark text inside a document
/// </summary>
/// <param name="watermarkText">text to show in the watermark</param>
/// <param name="diagonalOrientation">specify that the text orientation will be in a diagonal way</param>
public static OpenXmlPowerToolsDocument InsertWatermark(WmlDocument doc, string watermarkText, bool diagonalOrientation)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
Collection<XDocument> headers = new Collection<XDocument>();
if (HeaderAccessor.GetHeaderReference(document, HeaderType.First, 0) == null)
headers.Add(HeaderAccessor.AddNewHeader(document, HeaderType.First));
else
headers.Add(HeaderAccessor.GetHeader(document, HeaderType.First, 0));
if (HeaderAccessor.GetHeaderReference(document, HeaderType.Even, 0) == null)
headers.Add(HeaderAccessor.AddNewHeader(document, HeaderType.Even));
else
headers.Add(HeaderAccessor.GetHeader(document, HeaderType.Even, 0));
if (HeaderAccessor.GetHeaderReference(document, HeaderType.Default, 0) == null)
headers.Add(HeaderAccessor.AddNewHeader(document, HeaderType.Default));
else
headers.Add(HeaderAccessor.GetHeader(document, HeaderType.Default, 0));
foreach (XDocument header in headers)
{
var runElement = header.Descendants(ns + "r").FirstOrDefault();
if (runElement == null)
{
header.Root.Add(
new XElement(ns + "sdt",
new XElement(ns + "sdtContent",
new XElement(ns + "p",
new XElement(ns + "pPr",
new XElement(ns + "pStyle",
new XAttribute(ns + "val", "Header")
)
),
runElement = new XElement(ns + "r")
)
)
)
);
}
runElement.AddBeforeSelf(CreateWatermarkVml(watermarkText, diagonalOrientation));
}
HeaderAccessor.GetHeaderPart(document, HeaderType.First, 0).PutXDocument();
HeaderAccessor.GetHeaderPart(document, HeaderType.Even, 0).PutXDocument();
HeaderAccessor.GetHeaderPart(document, HeaderType.Default, 0).PutXDocument();
}
return streamDoc.GetModifiedDocument();
}
}
/// <summary>
/// Creates the markup for watermark displaying
/// </summary>
/// <param name="watermarkText">Text to include in markup</param>
/// <param name="diagonalOrientation">Orientation of text</param>
/// <returns>Watermark markup</returns>
private static XElement CreateWatermarkVml(string watermarkText, bool diagonalOrientation)
{
return new XElement(ns + "r",
new XElement(ns + "pict",
new XElement(vmlns + "shapetype",
new XAttribute("id", "_x0000_t136"),
new XAttribute("coordsize", "21600,21600"),
new XAttribute(officens + "spt", "136"),
new XAttribute("adj", "10800"),
new XAttribute("path", "m@7,l@8,m@5,21600l@6,21600e"),
new XElement(vmlns + "formulas",
new XElement(vmlns + "f",
new XAttribute("eqn", "sum #0 0 10800")
),
new XElement(vmlns + "f",
new XAttribute("eqn", "prod #0 2 1")
),
new XElement(vmlns + "f",
new XAttribute("eqn", "sum 21600 0 @1")
),
new XElement(vmlns + "f",
new XAttribute("eqn", "sum 0 0 @2")
),
new XElement(vmlns + "f",
new XAttribute("eqn", "sum 21600 0 @3")
),
new XElement(vmlns + "f",
new XAttribute("eqn", "if @0 @3 0")
),
new XElement(vmlns + "f",
new XAttribute("eqn", "if @0 21600 @1")
),
new XElement(vmlns + "f",
new XAttribute("eqn", "if @0 0 @2")
),
new XElement(vmlns + "f",
new XAttribute("eqn", "if @0 @4 21600")
),
new XElement(vmlns + "f",
new XAttribute("eqn", "mid @5 @6")
),
new XElement(vmlns + "f",
new XAttribute("eqn", "mid @8 @5")
),
new XElement(vmlns + "f",
new XAttribute("eqn", "mid @7 @8")
),
new XElement(vmlns + "f",
new XAttribute("eqn", "mid @6 @7")
),
new XElement(vmlns + "f",
new XAttribute("eqn", "sum @6 0 @5")
)
),
new XElement(vmlns + "path",
new XAttribute("textpathok", "t"),
new XAttribute(officens + "connecttype", "custom"),
new XAttribute(officens + "connectlocs", "@9,0;@10,10800;@11,21600;@12,10800"),
new XAttribute(officens + "connectangles", "270,180,90,0")
),
new XElement(vmlns + "textpath",
new XAttribute("on", "t"),
new XAttribute("fitshape", "t")
),
new XElement(vmlns + "handles",
new XElement(vmlns + "h",
new XAttribute("position", "#0,bottomRight"),
new XAttribute("xrange", "6629,14971")
)
),
new XElement(officens + "lock",
new XAttribute(vmlns + "ext", "edit"),
new XAttribute("text", "t"),
new XAttribute("shapetype", "t")
)
),
new XElement(vmlns + "shape",
new XAttribute("id", "PowerPlusWaterMarkObject98078923"),
new XAttribute(officens + "spid", "_x0000_s2055"),
new XAttribute("type", "#_x0000_t136"),
new XAttribute("style", diagonalOrientation ? diagonalWatermarkStyle : defaultWatermarkStyle),
new XAttribute(officens + "allowincell", "f"),
new XAttribute("fillcolor", "silver"),
new XAttribute("stroked", "f"),
new XElement(vmlns + "fill",
new XAttribute("opacity", ".5")
),
new XElement(vmlns + "textpath",
new XAttribute("style", "font-family:&quot;Calibri&quot;;font-size:1pt"),
new XAttribute("string", watermarkText)
)
)
)
);
}
/// <summary>
/// Gets the text related to watermark from a document
/// </summary>
/// <returns>Watermark text</returns>
public static string GetWatermarkText(WmlDocument doc)
{
IEnumerable<XElement> watermarkDescription = GetWatermark(doc);
if (watermarkDescription != null)
return
watermarkDescription
.Descendants(vmlns + "shape")
.Descendants(vmlns + "textpath")
.First()
.Attribute("string")
.Value;
else
return string.Empty;
}
/// <summary>
/// Gets the document structure related to watermark description
/// </summary>
/// <returns>Document structure related to watermark description</returns>
public static IEnumerable<XElement> GetWatermark(WmlDocument doc)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
// to get the watermark text, we have to look inside the document
// get the default header reference and get the header reference id part
XElement defaultHeaderReference = HeaderAccessor.GetHeaderReference(document, HeaderType.Default, 0);
if (defaultHeaderReference != null)
{
string headerReferenceId = defaultHeaderReference.Attribute(relationshipsns + "id").Value;
OpenXmlPart headerPart = document.MainDocumentPart.GetPartById(headerReferenceId);
if (headerPart != null)
{
XDocument headerPartXml = headerPart.GetXDocument();
return headerPartXml.Descendants(ns + "pict");
}
}
return null;
}
}
}
}

View File

@@ -0,0 +1,840 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace OpenXmlPowerTools
{
/// <summary>
/// Manages WordprocessingDocument content
/// </summary>
public class WordprocessingDocumentManager
{
private static XNamespace ns;
private static XNamespace relationshipsns;
private const string ValAttrName = "w:val";
static WordprocessingDocumentManager()
{
ns = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
relationshipsns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
}
/// <summary>
/// Creates the xml of a main document part content, with an empty body.
/// </summary>
/// <returns>the XDocument result</returns>
private static XDocument CreateMainDocumentPartXml()
{
return new XDocument(
new XElement(ns + "document",
new XAttribute(XNamespace.Xmlns + "w", ns),
new XAttribute(XNamespace.Xmlns + "r", relationshipsns),
new XElement(ns + "body")
)
);
}
/// <summary>
/// Creates the xml of a main document part content, adding some text inside
/// </summary>
/// <param name="text">Text to add inside the document</param>
private static XDocument CreateMainDocumentPartXml(string text)
{
return new XDocument(
new XElement(ns + "document",
new XAttribute(XNamespace.Xmlns + "w", ns),
new XAttribute(XNamespace.Xmlns + "r", relationshipsns),
new XElement(ns + "body",
new XElement(ns + "p",
new XElement(ns + "r",
new XElement(ns + "t", text)
)
)
)
)
);
}
/// <summary>
/// Creates the Xml of a main document part content, adding inside the body element a group of xml elements
/// </summary>
/// <param name="contents">XElement list with contents to add inside a document</param>
/// <returns>XDocument result</returns>
private static XDocument CreateMainDocumentPartXml(IEnumerable<XElement> contents)
{
return new XDocument(
new XElement(ns + "document",
new XAttribute(XNamespace.Xmlns + "w", ns),
new XAttribute(XNamespace.Xmlns + "r", relationshipsns),
new XElement(ns + "body",
contents
)
)
);
}
private static void LoadRelatedPart(XmlDocument mainDoc, XmlNode node, Stream stream)
{
XmlDocument partDoc = new XmlDocument();
partDoc.Load(stream);
XmlNode partNode = mainDoc.ImportNode(partDoc.DocumentElement, true);
if (partNode != null)
node.AppendChild(partNode);
}
private static XmlNamespaceManager createNameSpaceManager(XmlNameTable nameTable)
{
XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager(nameTable);
nameSpaceManager.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
nameSpaceManager.AddNamespace("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
nameSpaceManager.AddNamespace("a", "http://schemas.openxmlformats.org/drawingml/2006/main");
nameSpaceManager.AddNamespace("pic", "http://schemas.openxmlformats.org/drawingml/2006/picture");
nameSpaceManager.AddNamespace("wp", "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing");
nameSpaceManager.AddNamespace("v", "urn:schemas-microsoft-com:vml");
nameSpaceManager.AddNamespace("w10", "urn:schemas-microsoft-com:office:word");
nameSpaceManager.AddNamespace("o", "urn:schemas-microsoft-com:office:office");
return nameSpaceManager;
}
#if false
private class ListLevel
{
/// <summary>
/// constructor used when abstract list levels are instantiated
/// </summary>
public ListLevel(XmlNode levelNode, XmlNamespaceManager nsm)
{
this.id = getAttributeValue(levelNode, "w:ilvl");
XmlNode startValueNode = levelNode.SelectSingleNode("w:start", nsm);
if (startValueNode != null)
{
string startValueString = getAttributeValue(startValueNode, ValAttrName);
if (!String.IsNullOrEmpty(startValueString))
{
this.startValue = System.Convert.ToUInt32(startValueString, CultureInfo.InvariantCulture) - 1; // as I have to increment counters before each instance (to keep sub-list numbering from advancing too early, set startValue one lower;
}
}
this.started = false;
XmlNode levelTextNode = levelNode.SelectSingleNode("w:lvlText", nsm);
if (levelTextNode != null)
{
this.levelText = getAttributeValue(levelTextNode, ValAttrName);
}
XmlNode fontNode = levelNode.SelectSingleNode(".//w:rFonts", nsm);
if (fontNode != null)
{
this.font = getAttributeValue(fontNode, "w:hAnsi");
}
XmlNode enumTypeNode = levelNode.SelectSingleNode("w:numFmt", nsm);
if (enumTypeNode != null)
{
string type = getAttributeValue(enumTypeNode, ValAttrName);
// w:numFmt="bullet" indicates a bulleted list
this.isBullet = String.Compare(type, "bullet", StringComparison.OrdinalIgnoreCase) == 0;
// w:numFmt="lowerLetter" indicates letter conversion instead of number
this.isUpperLetter = String.Compare(type, "upperLetter", StringComparison.OrdinalIgnoreCase) == 0;
}
}
/// <summary>
/// copy constructor
/// </summary>
/// <param name="masterCopy"></param>
public ListLevel(ListLevel masterCopy)
{
this.abstractLevel = masterCopy;
this.id = masterCopy.ID;
this.levelText = masterCopy.LevelText;
this.startValue = masterCopy.StartValue;
this.started = false;
this.font = masterCopy.Font;
this.isBullet = masterCopy.IsBullet;
this.isUpperLetter = masterCopy.IsUpperLetter;
}
private ListLevel abstractLevel;
/// <summary>
/// Get overridden values
/// </summary>
/// <param name="levelNode"></param>
/// <param name="nsm"></param>
public void SetOverrides(XmlNode levelNode, XmlNamespaceManager nsm)
{
XmlNode startValueNode = levelNode.SelectSingleNode("w:start", nsm);
if (startValueNode != null)
{
string startValueString = getAttributeValue(startValueNode, ValAttrName);
this.startValue = System.Convert.ToUInt32(startValueString, CultureInfo.InvariantCulture) - 1; // as I have to increment counters before each instance (to keep sub-list numbering from advancing too early, set startValue one lower
}
XmlNode levelTextNode = levelNode.SelectSingleNode("w:lvlText", nsm);
if (levelTextNode != null)
{
this.levelText = getAttributeValue(levelTextNode, ValAttrName);
}
XmlNode fontNode = levelNode.SelectSingleNode("//w:rFonts", nsm);
if (fontNode != null)
{
this.font = getAttributeValue(fontNode, "w:hAnsi");
}
XmlNode enumTypeNode = levelNode.SelectSingleNode("w:numFmt", nsm);
if (enumTypeNode != null)
{
string type = getAttributeValue(enumTypeNode, ValAttrName);
// w:numFmt="bullet" indicates a bulleted list
this.isBullet = String.Compare(type, "bullet", StringComparison.OrdinalIgnoreCase) == 0;
}
}
public string FormatValue()
{
if (isUpperLetter)
return Convert.ToChar(('A' + CurrentValue - 1)).ToString(CultureInfo.InvariantCulture);
return CurrentValue.ToString(CultureInfo.InvariantCulture);
}
private string id;
/// <summary>
/// returns the ID of the level
/// </summary>
public string ID
{
get
{
return this.id;
}
}
private UInt32 startValue;
private bool started;
/// <summary>
/// start value of that level
/// </summary>
public UInt32 StartValue
{
get
{
return this.startValue;
}
}
private UInt32 counter;
/// <summary>
/// returns the current count of list items of that level
/// </summary>
public UInt32 CurrentValue
{
get
{
if (this.abstractLevel != null)
return this.abstractLevel.CurrentValue;
return this.counter;
}
}
/// <summary>
/// increments the current count of list items of that level
/// </summary>
public void IncrementCounter()
{
if (!started)
{
ResetCounter();
this.started = true;
}
if (this.abstractLevel != null)
this.abstractLevel.counter++;
else
this.counter++;
}
/// <summary>
/// resets the counter to the start value
/// </summary>
/// <id guid="823b5a3c-7501-4746-8dc4-7b098de5947a" />
/// <owner alias="ROrleth" />
public void ResetCounter()
{
if (this.abstractLevel != null)
this.abstractLevel.counter = this.startValue;
else
this.counter = this.startValue;
}
private string levelText;
/// <summary>
/// returns the indicated lvlText value
/// </summary>
public string LevelText
{
get
{
return this.levelText;
}
}
private string font;
/// <summary>
/// returns the font name
/// </summary>
public string Font
{
get
{
return this.font;
}
}
private bool isBullet;
/// <summary>
/// returns whether the enumeration type is a bulleted list or not
/// </summary>
public bool IsBullet
{
get
{
return this.isBullet;
}
}
private bool isUpperLetter;
/// <summary>
/// returns whether the enumeration type is upper-case letter or not
/// </summary>
public bool IsUpperLetter
{
get { return this.isUpperLetter; }
}
}
/// <summary>
/// private helper class to deal with abstract number lists
/// </summary>
private class AbstractListNumberingDefinition
{
private Dictionary<string, ListLevel> listLevels;
/// <summary>
/// constructor
/// </summary>
/// <param name="abstractNumNode"></param>
/// <param name="nsm"></param>
public AbstractListNumberingDefinition(XmlNode abstractNumNode, XmlNamespaceManager nsm)
{
string abstractNumString = getAttributeValue(abstractNumNode, "w:abstractNumId");
if (!String.IsNullOrEmpty(abstractNumString))
{
this.abstractNumDefId = abstractNumString;
this.readListLevelsFromAbsNode(abstractNumNode, nsm);
// find out whether there is a linked abstractNum definition that this needs to be populated from later on
XmlNode linkedStyleNode = abstractNumNode.SelectSingleNode("./w:numStyleLink", nsm);
if (linkedStyleNode != null)
{
this.linkedStyleId = getAttributeValue(linkedStyleNode, ValAttrName);
}
}
}
/// <summary>
/// update the level definitions from a linked abstractNum node
/// </summary>
/// <param name="linkedNode">
/// </param>
/// <param name="nsm">
/// </param>
/// <id guid="36473168-7947-41ea-8210-839bf07eded7" />
/// <owner alias="ROrleth" />
public void UpdateDefinitionFromLinkedStyle(XmlNode linkedNode, XmlNamespaceManager nsm)
{
if (!this.HasLinkedStyle)
return;
this.readListLevelsFromAbsNode(linkedNode, nsm);
}
/// <id guid="0e05c34c-f257-4c76-8916-3059af84e333" />
/// <owner alias="ROrleth" />
private void readListLevelsFromAbsNode(XmlNode absNumNode, XmlNamespaceManager nsm)
{
XmlNodeList levelNodes = absNumNode.SelectNodes("./w:lvl", nsm);
if (this.listLevels == null)
{
this.listLevels = new Dictionary<string, ListLevel>(levelNodes.Count);
}
// loop through the levels it defines and instantiate those
foreach (XmlNode levelNode in levelNodes)
{
ListLevel level = new ListLevel(levelNode, nsm);
this.listLevels[level.ID] = level;
}
}
private string linkedStyleId;
/// <summary>
/// returnts the ID of the linked style
/// </summary>
/// <id guid="ae2caeec-2d86-4e5f-b816-d508f6f2c893" />
/// <owner alias="ROrleth" />
public string LinkedStyleId
{
get
{
return this.linkedStyleId;
}
}
/// <summary>
/// indicates whether there is a linked style
/// </summary>
/// <id guid="75d74788-9839-448e-ae23-02d40e013d98" />
/// <owner alias="ROrleth" />
public bool HasLinkedStyle
{
get
{
return !String.IsNullOrEmpty(this.linkedStyleId);
}
}
private string abstractNumDefId;
/// <summary>
/// returns the ID of this abstract number list definition
/// </summary>
public string ID
{
get
{
return this.abstractNumDefId;
}
}
public Dictionary<String, ListLevel> ListLevels
{
get
{
return this.listLevels;
}
}
public int LevelCount
{
get
{
if (this.ListLevels != null)
return this.listLevels.Count;
else
return 0;
}
}
}
/// <summary>
/// private helper class to deal with number lists
/// </summary>
private class ListNumberingDefinition
{
/// <summary>
/// constructor
/// </summary>
/// <param name="numNode"></param>
/// <param name="nsm"></param>
/// <param name="abstractListDefinitions"></param>
public ListNumberingDefinition(XmlNode numNode, XmlNamespaceManager nsm, Dictionary<string, AbstractListNumberingDefinition> abstractListDefinitions)
{
this.listNumberId = getAttributeValue(numNode, "w:numId");
XmlNode abstractNumNode = numNode.SelectSingleNode("./w:abstractNumId", nsm);
if (abstractNumNode != null)
{
this.abstractListDefinition = abstractListDefinitions[getAttributeValue(abstractNumNode, ValAttrName)];
// Create local overrides for the list number levels
overrideLevels = new Dictionary<string, ListLevel>();
// propagate the level overrides into the current list number level definition
XmlNodeList levelOverrideNodes = numNode.SelectNodes("./w:lvlOverride", nsm);
if (levelOverrideNodes != null)
{
foreach (XmlNode overrideNode in levelOverrideNodes)
{
string overrideLevelId = getAttributeValue(overrideNode, "w:ilvl");
XmlNode node = overrideNode.SelectSingleNode("./w:lvl", nsm);
if (node == null)
node = overrideNode;
if (!String.IsNullOrEmpty(overrideLevelId))
{
ListLevel newLevel = new ListLevel(this.abstractListDefinition.ListLevels[overrideLevelId]);
newLevel.SetOverrides(node, nsm);
overrideLevels.Add(overrideLevelId, newLevel);
}
}
}
}
}
private AbstractListNumberingDefinition abstractListDefinition;
private Dictionary<String, ListLevel> overrideLevels;
/// <summary>
/// increment the occurrence count of the specified level, reset the occurrence count of derived levels
/// </summary>
/// <param name="level"></param>
public void IncrementCounter(string level)
{
FindLevel(level).IncrementCounter();
// here's a bit where the decision to use strings as level IDs was bad - I need to loop through the derived levels and reset their counters
UInt32 levelNumber = System.Convert.ToUInt32(level, CultureInfo.InvariantCulture) + 1;
string levelString = levelNumber.ToString(CultureInfo.InvariantCulture);
while (LevelExists(levelString))
{
FindLevel(levelString).ResetCounter();
levelNumber++;
levelString = levelNumber.ToString(CultureInfo.InvariantCulture);
}
}
private string listNumberId;
/// <summary>
/// numId of this list numbering schema
/// </summary>
public string ListNumberId
{
get
{
return this.listNumberId;
}
}
/// <summary>
/// returns a string containing the current state of the counters, up to the indicated level
/// </summary>
/// <param name="level"></param>
/// <returns></returns>
public string GetCurrentNumberString(string level)
{
string formatString = FindLevel(level).LevelText;
StringBuilder result = new StringBuilder();
string temp = string.Empty;
for (int i = 0; i < formatString.Length; i++)
{
temp = formatString.Substring(i, 1);
if (String.CompareOrdinal(temp, "%") == 0)
{
if (i < formatString.Length - 1)
{
string formatStringLevel = formatString.Substring(i + 1, 1);
// as it turns out, in the format string, the level is 1-based
UInt32 levelId = System.Convert.ToUInt32(formatStringLevel, CultureInfo.InvariantCulture) - 1;
result.Append(FindLevel(levelId.ToString(CultureInfo.InvariantCulture)).FormatValue());
i++;
}
}
else
{
result.Append(temp);
}
}
return result.ToString();
}
/// <summary>
/// retrieve the font name that was specified for the list string
/// </summary>
/// <param name="level"></param>
/// <returns></returns>
public string GetFont(string level)
{
return FindLevel(level).Font;
}
/// <summary>
/// retrieve whether the level was a bullet list type
/// </summary>
/// <param name="level"></param>
/// <returns></returns>
public bool IsBullet(string level)
{
return FindLevel(level).IsBullet;
}
/// <summary>
/// returns whether the specific level ID exists - in testing we've seen some referential integrity issues due to Word bugs
/// </summary>
/// <param name="level">
/// </param>
/// <returns>
/// </returns>
/// <id guid="b94c13b8-7273-4f6a-927b-178d685fbe0f" />
/// <owner alias="ROrleth" />
public bool LevelExists(string level)
{
if (this.overrideLevels.ContainsKey(level))
return true;
return this.abstractListDefinition.ListLevels.ContainsKey(level);
}
/// <summary>
/// returns whether the specific level ID exists - in testing we've seen some referential integrity issues due to Word bugs
/// </summary>
public ListLevel FindLevel(string level)
{
if (this.overrideLevels.ContainsKey(level))
return this.overrideLevels[level];
return this.abstractListDefinition.ListLevels[level];
}
}
/// <summary>
/// private helper class to deal with number definitions in styles
/// </summary>
private class StyleDefinition
{
private string m_Name;
private string m_LevelId;
private string m_NumId;
/// <summary>
/// constructor
/// </summary>
/// <param name="styleNode"></param>
/// <param name="nsm"></param>
/// <param name="styles"></param>
public StyleDefinition(XmlNode styleNode, XmlNamespaceManager nsm, Dictionary<string, StyleDefinition> styles)
{
m_Name = getAttributeValue(styleNode.ParentNode.ParentNode, "w:styleId");
XmlNode child = styleNode.ParentNode.ParentNode.SelectSingleNode("./w:basedOn", nsm);
m_LevelId = "0";
m_NumId = null;
if (child != null)
{
string basedOnName = getAttributeValue(child, ValAttrName);
if (styles.ContainsKey(basedOnName))
{
StyleDefinition basedOn = styles[basedOnName];
if (basedOn != null)
{
m_LevelId = basedOn.m_LevelId;
m_NumId = basedOn.m_NumId;
}
}
}
child = styleNode.SelectSingleNode("./w:ilvl", nsm);
if (child != null)
m_LevelId = getAttributeValue(child, ValAttrName);
child = styleNode.SelectSingleNode("./w:numId", nsm);
if (child != null)
m_NumId = getAttributeValue(child, ValAttrName);
}
public string Name
{
get { return m_Name; }
}
public void AddNumbering(XmlDocument mainDoc, XmlNode parent)
{
XmlNode numNode = mainDoc.CreateNode(XmlNodeType.Element, "w:numPr", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
XmlNode child = mainDoc.CreateNode(XmlNodeType.Element, "w:ilvl", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
XmlAttribute attr = mainDoc.CreateAttribute(ValAttrName, "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
attr.Value = m_LevelId;
child.Attributes.Append(attr);
numNode.AppendChild(child);
child = mainDoc.CreateNode(XmlNodeType.Element, "w:numId", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
attr = mainDoc.CreateAttribute(ValAttrName, "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
attr.Value = m_NumId;
child.Attributes.Append(attr);
numNode.AppendChild(child);
parent.AppendChild(numNode);
}
}
/// <summary>
/// count occurrences of numbered lists, save that as a hint on the numbered list node
/// </summary>
/// <param name="mainDoc"></param>
/// <param name="nsm"></param>
private static void HandleNumberedLists(XmlDocument mainDoc, XmlNamespaceManager nsm)
{
// count the number of different list numbering schemes
XmlNodeList numberNodes = mainDoc.SelectNodes("/w:document/w:numbering/w:num", nsm);
if (numberNodes.Count == 0)
{
return;
}
// initialize the abstract number list
XmlNodeList abstractNumNodes = mainDoc.SelectNodes("/w:document/w:numbering/w:abstractNum", nsm);
Dictionary<string, AbstractListNumberingDefinition> abstractListDefinitions = new Dictionary<string, AbstractListNumberingDefinition>(abstractNumNodes.Count);
Dictionary<string, ListNumberingDefinition> instanceListDefinitions = new Dictionary<string, ListNumberingDefinition>(numberNodes.Count);
// store the abstract list type definitions
foreach (XmlNode abstractNumNode in abstractNumNodes)
{
AbstractListNumberingDefinition absNumDef = new AbstractListNumberingDefinition(abstractNumNode, nsm);
abstractListDefinitions[absNumDef.ID] = absNumDef;
}
// now go through the abstract list definitions and update those that are linked to other styles
foreach (KeyValuePair<string, AbstractListNumberingDefinition> absNumDef in abstractListDefinitions)
{
if (absNumDef.Value.HasLinkedStyle)
{
// find the linked style
string linkStyleXPath = "/w:document/w:numbering/w:abstractNum/w:styleLink[@w:val=\"" + absNumDef.Value.LinkedStyleId + "\"]";
XmlNode linkedStyleNode = mainDoc.SelectSingleNode(linkStyleXPath, nsm);
if (linkedStyleNode != null)
{
absNumDef.Value.UpdateDefinitionFromLinkedStyle(linkedStyleNode.ParentNode, nsm);
}
}
}
// instantiate the list number definitions
foreach (XmlNode numNode in numberNodes)
{
ListNumberingDefinition listDef = new ListNumberingDefinition(numNode, nsm, abstractListDefinitions);
instanceListDefinitions[listDef.ListNumberId] = listDef;
}
// Get styles with numbering definitions
XmlNodeList stylesWithNumbers = mainDoc.SelectNodes("/w:document/w:styles/w:style/w:pPr/w:numPr", nsm);
Dictionary<string, StyleDefinition> styleDefinitions = new Dictionary<string, StyleDefinition>(stylesWithNumbers.Count);
foreach (XmlNode styleNode in stylesWithNumbers)
{
// Check to see if it is based on a style that is not in the definitions list yet?
StyleDefinition styleDef = new StyleDefinition(styleNode, nsm, styleDefinitions);
styleDefinitions[styleDef.Name] = styleDef;
}
XmlNodeList styleParagraphs = mainDoc.SelectNodes("//w:pPr/w:pStyle", nsm);
foreach (XmlNode paragraph in styleParagraphs)
{
string styleName = getAttributeValue(paragraph, ValAttrName);
if (!String.IsNullOrEmpty(styleName) && styleDefinitions.ContainsKey(styleName))
{
XmlNode oldNode = paragraph.ParentNode.SelectSingleNode("./w:numPr", nsm);
if (oldNode == null)
styleDefinitions[styleName].AddNumbering(mainDoc, paragraph.ParentNode);
}
}
XmlNodeList listNodes = mainDoc.SelectNodes("//w:numPr/w:ilvl", nsm);
foreach (XmlNode node in listNodes)
{
string levelId = getAttributeValue(node, ValAttrName);
XmlNode numIdNode = node.ParentNode.SelectSingleNode("./w:numId", nsm);
if (!String.IsNullOrEmpty(levelId) && numIdNode != null)
{
string numId = getAttributeValue(numIdNode, ValAttrName);
if (!String.IsNullOrEmpty(numId) && instanceListDefinitions.ContainsKey(numId) && instanceListDefinitions[numId].LevelExists(levelId))
{
XmlAttribute counterAttr = mainDoc.CreateAttribute("numString");
instanceListDefinitions[numId].IncrementCounter(levelId);
counterAttr.Value = instanceListDefinitions[numId].GetCurrentNumberString(levelId) + " ";
node.Attributes.Append(counterAttr);
string font = instanceListDefinitions[numId].GetFont(levelId);
if (!String.IsNullOrEmpty(font))
{
XmlAttribute fontAttr = mainDoc.CreateAttribute("numFont");
fontAttr.Value = font;
node.Attributes.Append(fontAttr);
}
if (instanceListDefinitions[numId].IsBullet(levelId))
{
XmlAttribute bulletAttr = mainDoc.CreateAttribute("isBullet");
bulletAttr.Value = "true";
node.Attributes.Append(bulletAttr);
}
}
}
}
}
internal static string getAttributeValue(XmlNode node, string name)
{
string value = string.Empty;
XmlAttribute attribute = node.Attributes[name];
if (attribute != null && attribute.Value != null)
{
value = attribute.Value;
}
return value;
}
#endif
}
}

View File

@@ -0,0 +1,550 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
using System.Xml;
namespace OpenXmlPowerTools
{
/// <summary>
/// Provides access to worksheet operations
/// </summary>
public class WorksheetAccessor
{
private static XNamespace ns;
private static XNamespace relationshipsns;
static WorksheetAccessor()
{
ns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
relationshipsns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
}
/// <summary>
/// Returns a worksheet located at a specific index
/// </summary>
/// <param name="worksheetIndex">Index for the worksheet to be returned</param>
/// <returns></returns>
public static WorksheetPart Get(SpreadsheetDocument document, int worksheetIndex)
{
return document.WorkbookPart.WorksheetParts.ElementAt(worksheetIndex);
}
/// <summary>
/// Returns the worksheet corresponding to the specified name
/// </summary>
/// <param name="worksheetName">Name for the worksheet to be returned</param>
/// <returns></returns>
public static WorksheetPart Get(SpreadsheetDocument document, string worksheetName)
{
XDocument workbook = document.WorkbookPart.GetXDocument();
XElement worksheetXelement = workbook.Root.Element(ns + "sheets")
.Elements(ns + "sheet")
.Where(s => s.Attribute("name").Value.ToLower().Equals(worksheetName.ToLower())).FirstOrDefault();
return (WorksheetPart)document.WorkbookPart
.GetPartById(worksheetXelement.Attribute(relationshipsns + "id").Value);
//return parentDocument.Document.WorkbookPart.WorksheetParts.FirstOrDefault(worksheet => worksheet.Uri.OriginalString.Split(new string[]{"/"},StringSplitOptions.RemoveEmptyEntries).Last<string>().ToLower().Equals(worksheetName.ToLower()+".xml"));
}
/// <summary>
/// Adds a given worksheet to the document
/// </summary>
/// <param name="worksheet">Worksheet document to add</param>
/// <returns>Worksheet part just added</returns>
public static WorksheetPart Add(SpreadsheetDocument doc, XDocument worksheet)
{
// Associates base content to a new worksheet part
WorkbookPart workbook = doc.WorkbookPart;
WorksheetPart worksheetPart = workbook.AddNewPart<WorksheetPart>();
worksheetPart.PutXDocument(worksheet);
// Associates the worksheet part to the workbook part
XDocument document = doc.WorkbookPart.GetXDocument();
int sheetId =
document.Root
.Element(ns + "sheets")
.Elements(ns + "sheet")
.Count() + 1;
int worksheetCount =
document.Root
.Element(ns + "sheets")
.Elements(ns + "sheet")
.Where(
t =>
t.Attribute("name").Value.StartsWith("sheet", StringComparison.OrdinalIgnoreCase)
)
.Count() + 1;
// Adds content to workbook document to reference worksheet document
document.Root
.Element(ns + "sheets")
.Add(
new XElement(ns + "sheet",
new XAttribute("name", string.Format("sheet{0}", worksheetCount)),
new XAttribute("sheetId", sheetId),
new XAttribute(relationshipsns + "id", workbook.GetIdOfPart(worksheetPart))
)
);
doc.WorkbookPart.PutXDocument();
return worksheetPart;
}
/// <summary>
/// Creates element structure needed to describe an empty worksheet
/// </summary>
/// <returns>Document with contents for an empty worksheet</returns>
private static XDocument CreateEmptyWorksheet()
{
XDocument document =
new XDocument(
new XElement(ns + "worksheet",
new XAttribute("xmlns", ns),
new XAttribute(XNamespace.Xmlns + "r", relationshipsns),
new XElement(ns + "sheetData")
)
);
return document;
}
/// <summary>
/// Adds a value to a cell inside a worksheet document
/// </summary>
/// <param name="worksheet">document to add values</param>
/// <param name="row">Row</param>
/// <param name="column">Column</param>
/// <param name="value">Value to add</param>
private static void AddValue(XDocument worksheet, int row, int column, string value)
{
//Set the cell reference
string cellReference = GetColumnId(column) + row.ToString();
double numericValue;
//Determining if value for cell is text or numeric
bool valueIsNumeric = double.TryParse(value, out numericValue);
//Creating the new cell element (markup)
XElement newCellXElement = valueIsNumeric ?
new XElement(ns + "c",
new XAttribute("r", cellReference),
new XElement(ns + "v", numericValue)
)
:
new XElement(ns + "c",
new XAttribute("r", cellReference),
new XAttribute("t", "inlineStr"),
new XElement(ns + "is",
new XElement(ns + "t", value)
)
);
// Find the row containing the cell to add the value to
XName rowName = "r";
XElement rowElement =
worksheet.Root
.Element(ns + "sheetData")
.Elements(ns + "row")
.Where(
t => t.Attribute(rowName).Value == row.ToString()
)
.FirstOrDefault();
if (rowElement == null)
{
//row element does not exist
//create a new one
rowElement = CreateEmptyRow(row);
//row elements must appear in order inside sheetData element
if (worksheet.Root
.Element(ns + "sheetData").HasElements)
{ //if there are more rows already defined at sheetData element
//find the row with the inmediate higher index for the row containing the cell to set the value to
XElement rowAfterElement = FindRowAfter(worksheet, row);
//if there is a row with an inmediate higher index already defined at sheetData
if (rowAfterElement != null)
{
//add the new row before the row with an inmediate higher index
rowAfterElement.AddBeforeSelf(rowElement);
}
else
{ //this row is going to be the one with the highest index (add it as the last element for sheetData)
worksheet.Root.Element(ns + "sheetData").Elements(ns + "row").Last().AddAfterSelf(rowElement);
}
}
else
{ //there are no other rows already defined at sheetData
//Add a new row elemento to sheetData
worksheet
.Root
.Element(ns + "sheetData")
.Add(
rowElement //= CreateEmptyRow(row)
);
}
//Add the new cell to the row Element
rowElement.Add(newCellXElement);
}
else
{
//row containing the cell to set the value to is already defined at sheetData
//look if cell already exist at that row
XElement currentCellXElement = rowElement
.Elements(ns + "c")
.Where(
t => t.Attribute("r").Value == cellReference
).FirstOrDefault();
if (currentCellXElement == null)
{ //cell element does not exist at row indicated as parameter
//find the inmediate right column for the cell to set the value to
XElement columnAfterXElement = FindColumAfter(worksheet, row, column);
if (columnAfterXElement != null)
{
//Insert the new cell before the inmediate right column
columnAfterXElement.AddBeforeSelf(newCellXElement);
}
else
{ //There is no inmediate right cell
//Add the new cell as the last element for the row
rowElement.Add(newCellXElement);
}
}
else
{
//cell alreay exist
//replace the current cell with that with the new value
currentCellXElement.ReplaceWith(newCellXElement);
}
}
}
/// <summary>
/// Finds the row with the inmediate higher index for a specific row
/// </summary>
/// <param name="worksheet">Worksheet for finding the row</param>
/// <param name="row">Row index to look for inmediate higher row</param>
/// <returns></returns>
private static XElement FindRowAfter(XDocument worksheet, int row)
{
XElement rowAfterXElement = worksheet.Root
.Element(ns + "sheetData")
.Elements(ns + "row").FirstOrDefault(r => System.Convert.ToInt32(r.Attribute("r").Value) > row);
return rowAfterXElement;
}
private static XElement FindColumAfter(XDocument worksheet, int row, int column)
{
XElement columnAfterXElement = worksheet.Root
.Element(ns + "sheetData")
.Elements(ns + "row").FirstOrDefault(r => System.Convert.ToInt32(r.Attribute("r").Value) == row)
.Elements(ns + "c").FirstOrDefault(c =>
GetColumnNumberFromCellReference(c.Attribute("r").Value, row) > GetColumnNumberFromCellReference(GetColumnId(column) + row, row));
return columnAfterXElement;
}
/// <summary>
/// Returns the column number from the cell reference received as parameter
/// </summary>
/// <param name="cellReference">Cell reference to obtain the column number from</param>
/// <param name="row">Row containing the cell to obtain the column number from</param>
/// <returns></returns>
private static int GetColumnNumberFromCellReference(string cellReference, int row)
{
int columnNumber = 0;
//Removing row number from cell reference
string columnReference = cellReference.Remove(cellReference.Length - row.ToString().Length);
int charPosition = 1;
int charValue = 0;
foreach (char c in columnReference)
{
//Getting the Unicode value for the current char in cell reference
charValue = System.Convert.ToInt32(c);
if (charPosition < columnReference.Length)
{ //we have not reached the last character in cell reference
//we need to multiply the charValue (from 0 to 25) by 26 and add the result of powering 26 to current char position in cell reference
//65 is the Unicode value for "A" letter
//26 is the number of letters in English alphabet
columnNumber += (((charValue - 65) * 26) + (System.Convert.ToInt32(Math.Pow(26, charPosition++))));
}
else
{ //This is the last character in cell reference
//we substract 64 instead of 65 because we want to get a one-based index for last character (instead of a zero-based index for previous characters)
columnNumber += (charValue - 64);
}
}
return columnNumber;
}
/// <summary>
/// Creates tags to describe an empty row
/// </summary>
/// <param name="row"></param>
/// <returns></returns>
private static XElement CreateEmptyRow(int row)
{
XElement rowElement =
new XElement(ns + "row",
new XAttribute("r", row.ToString())
);
return rowElement;
}
/// <summary>
/// Gets the column Id for a given column number
/// </summary>
/// <param name="columnNumber">Column number</param>
/// <returns>Column Id</returns>
public static string GetColumnId(int columnNumber)
{
int alfa = (int)'Z' - (int)'A' + 1;
if (columnNumber <= alfa)
return ((char)((int)'A' + columnNumber - 1)).ToString();
else
return
GetColumnId(
(int)((columnNumber - 1) / alfa)
) +
(
(char)(
(int)'A' + (int)((columnNumber - 1) % alfa)
)
).ToString();
}
/// <summary>
/// Creates a worksheet document and inserts data into it
/// </summary>
/// <param name="headerList">List of values that will act as the header</param>
/// <param name="valueTable">Values for worksheet content</param>
/// <param name="headerRow">Header row</param>
/// <returns></returns>
internal static WorksheetPart Create(SpreadsheetDocument document, List<string> headerList, string[][] valueTable, int headerRow)
{
XDocument xDocument = CreateEmptyWorksheet();
for (int i = 0; i < headerList.Count; i++)
{
AddValue(xDocument, headerRow, i + 1, headerList[i]);
}
int rows = valueTable.GetLength(0);
int cols = valueTable[0].GetLength(0);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
AddValue(xDocument, i + headerRow + 1, j + 1, valueTable[i][j]);
}
}
WorksheetPart part = Add(document, xDocument);
return part;
}
/// <summary>
/// Get value for a cell in a worksheet
/// </summary>
/// <param name="worksheet"></param>
/// <param name="column"></param>
/// <param name="row"></param>
/// <remarks>Author:Johann Granados Company: Staff DotNet Creation Date: 8/30/2008</remarks>
/// <returns></returns>
public static string GetValue(SpreadsheetDocument document, WorksheetPart worksheet, short column, int row)
{
XDocument worksheetXDocument = XDocument.Load(new XmlTextReader(worksheet.GetStream()));
XElement cellValueXElement = GetCell(worksheetXDocument, column, row);
if (cellValueXElement != null)
{
if (cellValueXElement.Element(ns + "v") != null)
{
return GetSharedString(document, System.Convert.ToInt32(cellValueXElement.Value));
}
else
{
return cellValueXElement.Element(ns + "is").Element(ns + "t").Value;
}
}
else
{
return string.Empty;
}
}
private static string GetSharedString(SpreadsheetDocument document, int index)
{
XDocument sharedStringsXDocument = XDocument.Load(new XmlTextReader(document.WorkbookPart.SharedStringTablePart.GetStream()));
return sharedStringsXDocument.Root.Elements().ElementAt<XElement>(index).Value;
}
/// <summary>
/// Set the value for a specific cell
/// </summary>
/// <param name="worksheet">Worksheet part containing the cell to be affected</param>
/// <param name="fromColumn">Initial column for setting the value</param>
/// <param name="fromRow">Initial row for setting the value</param>
/// <param name="toColumn">Final column for setting the value</param>
/// <param name="toRow">Final row for setting the value</param>
/// <param name="value">Cell value</param>
public static OpenXmlPowerToolsDocument SetCellValue(SmlDocument doc, string worksheetName, int fromRow, int toRow, int fromColumn, int toColumn, string value)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (SpreadsheetDocument document = streamDoc.GetSpreadsheetDocument())
{
WorksheetPart worksheet = Get(document, worksheetName);
XDocument worksheetXDocument = XDocument.Load(new XmlTextReader(worksheet.GetStream()));
for (int row = fromRow; row <= toRow; row++)
{
for (int col = fromColumn; col <= toColumn; col++)
{
AddValue(worksheetXDocument, row, col, value);
}
}
XmlWriter worksheetWriter = XmlTextWriter.Create(worksheet.GetStream(System.IO.FileMode.Create));
worksheetXDocument.WriteTo(worksheetWriter);
worksheetWriter.Flush();
worksheetWriter.Close();
}
return streamDoc.GetModifiedDocument();
}
}
/// <summary>
/// Apply a cell style to a specific cell
/// </summary>
/// <param name="worksheet">worksheet containing the cell to be affected</param>
/// <param name="fromColumn">Starting Cell Column</param>
/// <param name="toColumn">Ending Cell Column</param>
/// <param name="fromRow">Starting Cell Row</param>
/// <param name="toRow">Ending Cell Row</param>
/// <param name="cellStyle">Cell Style</param>
public static OpenXmlPowerToolsDocument SetCellStyle(SmlDocument doc, string worksheetName, short fromColumn, short toColumn, int fromRow, int toRow, string cellStyle)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (SpreadsheetDocument document = streamDoc.GetSpreadsheetDocument())
{
WorksheetPart worksheet = Get(document, worksheetName);
XDocument worksheetXDocument = XDocument.Load(new XmlTextReader(worksheet.GetStream()));
for (int row = fromRow; row <= toRow; row++)
{
for (short col = fromColumn; col <= toColumn; col++)
{
XElement cellXelement = GetCell(worksheetXDocument, col, row);
cellXelement.SetAttributeValue("s", SpreadSheetStyleAccessor.GetCellStyleIndex(document, cellStyle));
}
}
XmlWriter worksheetWriter = XmlTextWriter.Create(worksheet.GetStream(System.IO.FileMode.Create));
worksheetXDocument.WriteTo(worksheetWriter);
worksheetWriter.Flush();
worksheetWriter.Close();
}
return streamDoc.GetModifiedDocument();
}
}
/// <summary>
/// Set the width for a range of columns
/// </summary>
/// <param name="worksheet">Worksheet containing the columns to be affected</param>
/// <param name="fromColumn">Initial column to affect</param>
/// <param name="toColumn">Final column to affect</param>
/// <param name="width">Column width</param>
public static OpenXmlPowerToolsDocument SetColumnWidth(SmlDocument doc, string worksheetName, short fromColumn, short toColumn, int width)
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
{
using (SpreadsheetDocument document = streamDoc.GetSpreadsheetDocument())
{
WorksheetPart worksheet = Get(document, worksheetName);
//Get the worksheet markup
XDocument worksheetXDocument = XDocument.Load(new XmlTextReader(worksheet.GetStream()));
//Look for worksheet cols element
XElement colsXElement = worksheetXDocument.Root.Element(ns + "cols");
if (colsXElement == null)
{
//cols elements does not exist
//create a new one
colsXElement = new XElement(ns + "cols");
//create a new col element (for setting the width)
//the col element could span more than one column -span is controlled by min (initial column) and max (final column) attributes
colsXElement.Add(new XElement(ns + "col",
new XAttribute("min", fromColumn.ToString()),
new XAttribute("max", toColumn.ToString()),
new XAttribute("width", width.ToString()),
new XAttribute("customWidth", "1")));
//cols element must be added before worksheet sheetData element
worksheetXDocument.Root.Element(ns + "sheetData").AddBeforeSelf(colsXElement);
}
else
{
//look for a col element for the column range indicated for fromColumn and toColumn
XElement colXElement = colsXElement.Elements(ns + "col")
.Where(c => (System.Convert.ToInt32(c.Attribute("min").Value) == fromColumn) && (System.Convert.ToInt32(c.Attribute("max").Value) == toColumn)).FirstOrDefault();
if (colXElement != null)
{
//col element does exist
//change its width value
colXElement.SetAttributeValue("width", width);
}
else
{
//col element does not exist
//create a new one
colsXElement.Add(new XElement(ns + "col",
new XAttribute("min", fromColumn.ToString()),
new XAttribute("max", toColumn.ToString()),
new XAttribute("width", width.ToString()),
new XAttribute("customWidth", "1")));
}
}
//Update the worksheet part markup at worksheet part stream
XmlWriter worksheetWriter = XmlTextWriter.Create(worksheet.GetStream(System.IO.FileMode.Create));
worksheetXDocument.WriteTo(worksheetWriter);
worksheetWriter.Flush();
worksheetWriter.Close();
}
return streamDoc.GetModifiedDocument();
}
}
/// <summary>
/// Return a XElement representing the markup for a specific cell in a SpreadsheetML document
/// </summary>
/// <param name="worksheetXDocument">Worksheet markup</param>
/// <param name="column">Cell column</param>
/// <param name="row">Cell row</param>
/// <returns></returns>
private static XElement GetCell(XDocument worksheetXDocument, short column, int row)
{
return worksheetXDocument.Root
.Element(ns + "sheetData")
.Elements(ns + "row")
.Where(
r => r.Attribute("r").Value.Equals(row.ToString())).FirstOrDefault<XElement>()
.Elements(ns + "c").Where(c => c.Attribute("r").Value.Equals(GetColumnId(column) + row.ToString())).FirstOrDefault<XElement>();
}
}
}

View File

@@ -0,0 +1,88 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
[Cmdlet(VerbsCommon.Add, "OpenXmlContent", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class AddOpenXmlContentCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
string[] xmlPartPaths;
string xpathInsertionPoint;
string xmlContent;
[Parameter(Position = 2, Mandatory = true, HelpMessage = "Custom Xml part path")]
[ValidateNotNullOrEmpty]
public string[] PartPath
{
get
{
return xmlPartPaths;
}
set
{
xmlPartPaths = value;
}
}
[Parameter(Position = 3, Mandatory = true, HelpMessage = "Insertion point location")]
[ValidateNotNullOrEmpty]
public string InsertionPoint
{
get
{
return xpathInsertionPoint;
}
set
{
xpathInsertionPoint = value;
}
}
[Parameter(Position = 4, Mandatory = true, HelpMessage = "Xml to insert")]
[ValidateNotNullOrEmpty]
public string Content
{
get
{
return xmlContent;
}
set
{
xmlContent = value;
}
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Add-OpenXmlContent"))
{
try
{
OutputDocument(PowerToolsExtensions.InsertXml(document, xmlPartPaths, xpathInsertionPoint, xmlContent));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,66 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
using System.Collections.Generic;
using System.Linq;
namespace OpenXmlPowerTools.Commands
{
[Cmdlet(VerbsCommon.Add, "OpenXmlDigitalSignature", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class AddOpenXmlDigitalSignatureCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
private string certificate;
[Parameter(
Position = 2,
Mandatory = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "Digital certificate path")
]
[ValidateNotNullOrEmpty]
public string Certificate
{
get
{
return certificate;
}
set
{
certificate = value;
}
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
IEnumerable<string> certList = SessionState.Path.GetResolvedPSPathFromPSPath(certificate).Select(e => e.Path);
foreach (var document in AllDocuments("Add-OpenXmlDigitalSignature"))
{
try
{
OutputDocument(DigitalSignatureAccessor.Insert(document, certList));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,93 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2008.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Add-OpenXmlIndex cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Add, "OpenXmlDocumentIndex", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class AddOpenXmlDocumentIndexCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
string stylesSourcePath = "";
bool addDefaultStyles = false;
[Parameter(
Position = 2,
Mandatory = false,
HelpMessage = "Path of the styles file used to get the styles of the index")
]
[ValidateNotNullOrEmpty]
public string StylesSourcePath
{
get
{
return stylesSourcePath;
}
set
{
stylesSourcePath = value;
}
}
[Parameter(
Mandatory = false,
HelpMessage = "Specifies if the styles used in the index must be added to the document")
]
[ValidateNotNullOrEmpty]
public SwitchParameter AddDefaultStyles
{
get
{
return addDefaultStyles;
}
set
{
addDefaultStyles = value;
}
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Add-OpenXmlDocumentIndex"))
{
try
{
using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(document))
{
using (WordprocessingDocument doc = streamDoc.GetWordprocessingDocument())
{
IndexAccessor.Generate(doc);
StyleAccessor.CreateIndexStyles(doc, stylesSourcePath, addDefaultStyles);
}
OutputDocument(streamDoc.GetModifiedDocument());
}
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,64 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Add-OpenXmlDocumentTOA cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Add, "OpenXmlDocumentTOA", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class AddOpenXmlDocumentTOACmdlet : PowerToolsModifierCmdlet
{
#region Parameters
[Parameter(
Position = 2,
Mandatory = true,
HelpMessage = "XPath where the table of contents will be created.")
]
[ValidateNotNullOrEmpty]
public string InsertionPoint;
[Parameter(
Position = 3,
Mandatory = true,
HelpMessage = "Choices of how the table of contents will be created.")
]
[ValidateNotNullOrEmpty]
public string Switches;
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Add-OpenXmlDocumentTOA"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(ReferenceAdder.AddToa((WmlDocument)document, InsertionPoint, Switches, null));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,63 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Add-OpenXmlDocumentTOC cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Add, "OpenXmlDocumentTOC", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class AddOpenXmlDocumentTOCCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
[Parameter(
Position = 2,
Mandatory = true,
HelpMessage = "XPath where the table of contents will be created.")
]
[ValidateNotNullOrEmpty]
public string InsertionPoint;
[Parameter(
Position = 3,
Mandatory = true,
HelpMessage = "Choices of how the table of contents will be created.")
]
[ValidateNotNullOrEmpty]
public string Switches;
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Add-OpenXmlDocumentTOC"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(ReferenceAdder.AddToc((WmlDocument)document , InsertionPoint, Switches, null, null));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,63 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Add-OpenXmlDocumentTOF cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Add, "OpenXmlDocumentTOF", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class AddOpenXmlDocumentTOFCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
[Parameter(
Position = 2,
Mandatory = true,
HelpMessage = "XPath where the table of figures will be created.")
]
[ValidateNotNullOrEmpty]
public string InsertionPoint;
[Parameter(
Position = 3,
Mandatory = true,
HelpMessage = "Choices of how the table of contents will be created.")
]
[ValidateNotNullOrEmpty]
public string Switches;
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Add-OpenXmlDocumentTOF"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(ReferenceAdder.AddTof((WmlDocument)document, InsertionPoint, Switches, null));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,107 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Linq;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
[Cmdlet(VerbsCommon.Add, "OpenXmlPicture", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class AddOpenXmlPictureCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
private string xpathInsertionPoint;
private string picturePath;
private System.Drawing.Image image;
[Parameter(Position = 2, Mandatory = true, HelpMessage = "Insertion point location")]
[ValidateNotNullOrEmpty]
public string InsertionPoint
{
get
{
return xpathInsertionPoint;
}
set
{
xpathInsertionPoint = value;
}
}
[Parameter(Position = 3, Mandatory = false, HelpMessage = "Picture path")]
[ValidateNotNullOrEmpty]
public string PicturePath
{
get
{
return picturePath;
}
set
{
picturePath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path;
}
}
/// <summary>
/// ImageFile parameter
/// </summary>
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
HelpMessage = "Image object to be inserted")
]
[ValidateNotNullOrEmpty]
public System.IO.FileInfo ImageFile
{
get
{
return new System.IO.FileInfo(picturePath == null ? "." : picturePath);
}
set
{
picturePath = value.FullName;
}
}
#endregion
#region Cmdlet Overrides
/// <summary>
/// Entry point for PowerShell cmdlets
/// </summary>
protected override void ProcessRecord()
{
string picName = "PowerToolsPicture";
if (image == null && picturePath != null)
{
image = System.Drawing.Image.FromFile(picturePath, true);
picName = picturePath.Substring(picturePath.LastIndexOf('\\') + 1);
}
foreach (var document in AllDocuments("Add-OpenXmlPicture"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(PictureAccessor.Insert((WmlDocument)document, xpathInsertionPoint, image, picName));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,211 @@
 /***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Cmdlet for adding a new table to a worksheet in a SpreadsheetML document
/// </summary>
[Cmdlet(VerbsCommon.Add, "OpenXmlSpreadSheetTable", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class AddOpenXmlSpreadSheetTableCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
private string tableStyle = string.Empty;
private SwitchParameter hasHeaders =false;
private short fromColumn;
private short toColumn;
private int fromRow;
private int toRow;
private string worksheetName;
[Parameter(Position = 2,
Mandatory = true,
HelpMessage = "Table Style Name")]
[ValidateNotNullOrEmpty]
public string TableStyle
{
get
{
return tableStyle;
}
set
{
tableStyle = value;
}
}
/// <summary>
/// Use Headers parameter
/// </summary>
[Parameter(
Mandatory = false,
HelpMessage = "Has Headers?")]
[ValidateNotNullOrEmpty]
public SwitchParameter HasHeaders
{
get
{
return hasHeaders;
}
set
{
hasHeaders = value;
}
}
/// <summary>
/// Initial table column
/// </summary>
[Parameter(Position = 3,
Mandatory = true,
HelpMessage = "Initial table column")]
[ValidateNotNullOrEmpty]
public short FromColumn
{
get
{
return fromColumn;
}
set
{
if (value > 0)
{
fromColumn = value;
}
else
{
throw new System.Management.Automation.ParameterBindingException("Initial Table Column must be greater than 0");
}
}
}
/// <summary>
/// Final table column
/// </summary>
[Parameter(Position = 4,
Mandatory = true,
HelpMessage = "Final table column")]
[ValidateNotNullOrEmpty]
public short ToColumn
{
get
{
return toColumn;
}
set
{
if (value > 0)
{
toColumn = value;
}
else
{
throw new System.Management.Automation.ParameterBindingException("Final table column must be greater than 0");
}
}
}
/// <summary>
/// Initial table row
/// </summary>
[Parameter(Position = 5,
Mandatory = true,
HelpMessage = "Initial table row")]
[ValidateNotNullOrEmpty]
public int FromRow
{
get
{
return fromRow;
}
set
{
if (value > 0)
{
fromRow = value;
}
else
{
throw new System.Management.Automation.ParameterBindingException("Initial Table Row must be greater than 0");
}
}
}
/// <summary>
/// Final table row
/// </summary>
[Parameter(Position = 6,
Mandatory = true,
HelpMessage = "Final table row")]
[ValidateNotNullOrEmpty]
public int ToRow
{
get
{
return toRow;
}
set
{
if (value > 0)
{
toRow = value;
}
else
{
throw new System.Management.Automation.ParameterBindingException("Final table row must be greater than 0");
}
}
}
/// <summary>
/// Index for worksheet to add the table to
/// </summary>
[Parameter(Position = 7,
Mandatory = true,
HelpMessage = "Worksheet name to add the table to")]
[ValidateNotNullOrEmpty]
public string WorksheetName
{
get
{
return worksheetName;
}
set
{
worksheetName = value;
}
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Add-OpenXmlSpreadSheetTable"))
{
try
{
if (!(document is SmlDocument))
throw new PowerToolsDocumentException("Not a spreadsheet document.");
OutputDocument(SpreadSheetTableAccessor.Add((SmlDocument)document, worksheetName, tableStyle, hasHeaders, fromColumn, toColumn, fromRow, toRow));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,70 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Validation;
namespace OpenXmlPowerTools.Commands
{
public class ValidationInfo
{
public OpenXmlPowerToolsDocument Document;
public string FileName;
public string Description;
public ValidationErrorType ErrorType;
public string Id;
public OpenXmlElement Node;
public OpenXmlPart Part;
public string XPath;
public OpenXmlElement RelatedNode;
public OpenXmlPart RelatedPart;
public ValidationInfo(OpenXmlPowerToolsDocument doc, ValidationErrorInfo err)
{
Document = doc;
FileName = doc.FileName;
Description = err.Description;
ErrorType = err.ErrorType;
Id = err.Id;
Node = err.Node;
Part = err.Part;
XPath = err.Path.XPath;
RelatedNode = err.RelatedNode;
RelatedPart = err.RelatedPart;
}
}
[Cmdlet(VerbsLifecycle.Confirm, "OpenXmlValid")]
[OutputType("ValidationInfo")]
public class ConfirmOpenXmlValidCmdlet : PowerToolsReadOnlyCmdlet
{
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Confirm-OpenXmlValid"))
{
try
{
foreach (ValidationErrorInfo item in PowerToolsExtensions.ValidateXml(document))
WriteObject(new ValidationInfo(document, item), true);
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,48 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
[Cmdlet(VerbsData.Edit, "OpenXmlChange", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class EditOpenXmlChangeCmdlet : PowerToolsModifierCmdlet
{
[Parameter(Mandatory = false)]
public SwitchParameter Accept;
// Future option
//[Parameter(Mandatory = false)]
//public SwitchParameter Reject;
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Edit-OpenXmlChange"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
if (Accept)
OutputDocument(RevisionAccepter.AcceptRevisions((WmlDocument)document));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,247 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Management.Automation;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools.Commands
{
[Cmdlet(VerbsData.Export, "OpenXmlSpreadsheet", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class ExportOpenXmlSpreadsheetCmdlet : PowerToolsCreateCmdlet
{
#region Parameters
private PSObject[] pipeObjects;
private Collection<PSObject> processedObjects = new Collection<PSObject>();
private List<string> columnsToChart;
string headerColumn;
string outputPath;
bool displayChart;
private int initialRow = 1;
ChartType chartType;
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = false,
HelpMessage = "Path of file in which to store results")
]
public string OutputPath
{
get
{
return outputPath;
}
set
{
outputPath = Path.Combine(SessionState.Path.CurrentLocation.Path, value);
}
}
/// <summary>
/// InputObject parameter
/// </summary>
[Parameter(
ValueFromPipeline = true,
HelpMessage = "Objects passed by pipe to be included in spreadsheet")
]
public PSObject[] InputObject
{
get
{
return pipeObjects;
}
set
{
pipeObjects = value;
}
}
/// <summary>
/// Chart parameter
/// </summary>
[Parameter(
Mandatory = false,
ValueFromPipeline = false,
ParameterSetName = "charting",
HelpMessage = "Whether generate a chart from loaded data or not")
]
public SwitchParameter Chart
{
get
{
return displayChart;
}
set
{
displayChart = value;
}
}
/// <summary>
/// ChartType parameter
/// </summary>
[Parameter(
Mandatory = false,
ValueFromPipeline = false,
ParameterSetName = "charting",
HelpMessage = "Type of chart to be generated")
]
public ChartType ChartType
{
get
{
return chartType;
}
set
{
chartType = value;
}
}
/// <summary>
/// ColumnsToChart parameter
/// </summary>
[Parameter(
Mandatory = false,
ValueFromPipeline = false,
ParameterSetName = "charting",
HelpMessage = "Columns from data to be used as series in chart")
]
public List<string> ColumnsToChart
{
get
{
return columnsToChart;
}
set
{
columnsToChart = value;
}
}
/// <summary>
/// HeaderColumn parameter
/// </summary>
[Parameter(
Mandatory = false,
ValueFromPipeline = false,
ParameterSetName = "charting",
HelpMessage = "Column from data to be used as category in chart")
]
public string HeaderColumn
{
get
{
return headerColumn;
}
set
{
headerColumn = value;
}
}
[Parameter(
Mandatory = false,
ValueFromPipeline = false,
HelpMessage = "Header Row")
]
[ValidateNotNullOrEmpty]
public int InitialRow
{
get
{
return initialRow;
}
set
{
initialRow = value;
}
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
if (pipeObjects != null)
{
foreach (PSObject pipeObject in pipeObjects)
processedObjects.Add(pipeObject);
}
}
protected override void EndProcessing()
{
if (!File.Exists(outputPath) || ShouldProcess(outputPath, "Export-OpenXmlSpreadsheet"))
{
using (OpenXmlMemoryStreamDocument streamDoc = OpenXmlMemoryStreamDocument.CreateSpreadsheetDocument())
{
using (SpreadsheetDocument document = streamDoc.GetSpreadsheetDocument())
{
if (processedObjects.Count > 0)
{
List<string> headerList = new List<string>();
foreach (PSPropertyInfo propertyInfo in processedObjects[0].Properties)
{
headerList.Add(propertyInfo.Name.ToUpper());
}
// Stores into a matrix all properties of objects passed as parameter
int rowLength = headerList.Count;
int rowCount = processedObjects.Count;
string[][] valueMatrix = new string[rowCount][];
int currentRow = 0, currentColumn = 0;
foreach (PSObject obj in processedObjects)
{
currentColumn = 0;
valueMatrix[currentRow] = new string[rowLength];
foreach (PSPropertyInfo propertyInfo in obj.Properties)
{
try
{
if (propertyInfo.Value != null)
{
valueMatrix[currentRow][currentColumn] = propertyInfo.Value.ToString();
}
}
// Suppress errors on properties that cannot be read, but write the information to debug output.
catch (GetValueInvocationException e)
{
WriteDebug(string.Format(CultureInfo.InvariantCulture, "Exception ({0}) at Object {1}, property {2}", e.Message, currentRow, currentColumn));
}
currentColumn++;
}
currentRow++;
}
if (displayChart)
SpreadsheetDocumentManager.Create(document, headerList, valueMatrix, chartType, headerColumn, columnsToChart, initialRow);
else
SpreadsheetDocumentManager.Create(document, headerList, valueMatrix, initialRow);
}
}
OpenXmlPowerToolsDocument output = streamDoc.GetModifiedDocument();
output.FileName = outputPath;
OutputDocument(output);
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,163 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Xml.Linq;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Transform-OpenXmlToHtml cmdlet
/// </summary>
[Cmdlet(VerbsData.Export, "OpenXmlToHtml", SupportsShouldProcess = true)]
public class ExportOpenXmlToHtmlCmdlet : PowerToolsReadOnlyCmdlet
{
#region Parameters
[Parameter(
Position = 1,
Mandatory = true,
HelpMessage = "Title for the HTML page")
]
public string PageTitle;
[Parameter(
Position = 2,
Mandatory = false,
HelpMessage = "Name of the html output file")
]
public string OutputPath;
[Parameter(
Position = 3,
Mandatory = false,
HelpMessage = "Folder where image files are going to be placed")
]
public string ImageFolder;
[Parameter(
Position = 4,
Mandatory = false,
HelpMessage = "Prefix for image file names")
]
public string ImagePrefix;
[Parameter(
Position = 5,
Mandatory = false,
HelpMessage = "CSS file name")
]
public string CssPath;
[Parameter(
Position = 6,
Mandatory = false,
HelpMessage = "CSS class name prefix")
]
public string CssClassPrefix;
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Export-OpenXmlToHtml"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
FileInfo info = null;
if (document.FileName != null)
info = new FileInfo(document.FileName);
string htmlFileName;
if (OutputPath != null)
htmlFileName = System.IO.Path.Combine(SessionState.Path.CurrentLocation.Path, OutputPath);
else
{
if (info == null)
throw new ArgumentException("No output file name available.");
htmlFileName = System.IO.Path.Combine(info.DirectoryName, info.Name.Substring(0, info.Name.Length - info.Extension.Length) + ".html");
}
string imageFolder;
FileInfo outputInfo = new FileInfo(htmlFileName);
if (ImageFolder != null)
imageFolder = SessionState.Path.GetResolvedPSPathFromPSPath(ImageFolder).First().Path;
else
imageFolder = System.IO.Path.Combine(outputInfo.DirectoryName, "images");
DirectoryInfo imageFolderInfo = new DirectoryInfo(imageFolder);
if (!imageFolderInfo.Exists)
imageFolderInfo.Create();
HtmlConverterSettings settings = new HtmlConverterSettings();
settings.PageTitle = PageTitle;
if (CssPath != null)
{
settings.CssClassPrefix = CssClassPrefix;
// Read CSS file into a string
string cssFileName = SessionState.Path.GetResolvedPSPathFromPSPath(CssPath).First().Path;
settings.Css = File.ReadAllText(cssFileName);
}
int imageCounter = 0;
XElement html = HtmlConverter.ConvertToHtml((WmlDocument)document, settings,
imageInfo =>
{
++imageCounter;
string extension = imageInfo.ContentType.Split('/')[1].ToLower();
ImageFormat imageFormat = null;
if (extension == "png")
{
// Convert png to jpeg.
extension = "jpeg";
imageFormat = ImageFormat.Jpeg;
}
else if (extension == "bmp")
imageFormat = ImageFormat.Bmp;
else if (extension == "jpeg")
imageFormat = ImageFormat.Jpeg;
else if (extension == "tiff")
imageFormat = ImageFormat.Tiff;
// If the image format isn't one that we expect, ignore it,
// and don't return markup for the link.
if (imageFormat == null)
return null;
string imageFileName = System.IO.Path.Combine(imageFolder, "image" + imageCounter.ToString() + "." + extension);
try
{
imageInfo.Bitmap.Save(imageFileName, imageFormat);
}
catch (System.Runtime.InteropServices.ExternalException)
{
return null;
}
XElement img = new XElement(Xhtml.img,
new XAttribute(NoNamespace.src, imageFileName),
imageInfo.ImgStyleAttribute,
imageInfo.AltText != null ?
new XAttribute(NoNamespace.alt, imageInfo.AltText) : null);
return img;
});
File.WriteAllText(htmlFileName, html.ToStringNewLineOnAttributes());
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,107 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System.IO;
using System.Collections.Generic;
using System.Management.Automation;
using System.Linq;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Export-OpenXmlWordprocessing cmdlet
/// </summary>
[Cmdlet("Export", "OpenXmlWordprocessing", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class ExportOpenXmlWordprocessingCmdlet : PowerToolsCreateCmdlet
{
#region Parameters
private string outputPath;
private string[] text;
private List<string> processedObjects = new List<string>();
/// <summary>
/// OutputPath parameter
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
HelpMessage = "Path of file to store export results")
]
[ValidateNotNullOrEmpty]
public string OutputPath
{
get
{
return outputPath;
}
set
{
outputPath = Path.Combine(SessionState.Path.CurrentLocation.Path, value);
}
}
[Parameter(
Position = 1,
ValueFromPipeline = true,
Mandatory = true,
HelpMessage = "Text to insert in the new wordprocessing document")
]
[AllowEmptyString]
public string[] Text
{
get
{
return text;
}
set
{
text = value;
}
}
#endregion
#region Cmdlet Overrides
/// <summary>
/// Entry point for PowerShell cmdlets
/// </summary>
protected override void ProcessRecord()
{
if (text != null)
{
foreach (string item in text)
processedObjects.Add(item);
}
}
protected override void EndProcessing()
{
if (PassThru || !File.Exists(outputPath) || ShouldProcess(outputPath, "Export-OpenXmlWordprocessing"))
{
using (OpenXmlMemoryStreamDocument streamDoc = OpenXmlMemoryStreamDocument.CreateWordprocessingDocument())
{
using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
{
if (processedObjects.Count > 0)
PowerToolsExtensions.SetContent(document, processedObjects.Select(e => new XElement(W.p, new XElement(W.r, new XElement(W.t, new XAttribute(XNamespace.Xml + "space", "preserve"), e)))));
}
OpenXmlPowerToolsDocument output = streamDoc.GetModifiedDocument();
output.FileName = outputPath;
OutputDocument(output);
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,134 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.IO;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Get-OpenXmlBackground cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Get, "OpenXmlBackground", SupportsShouldProcess = true)]
public class GetOpenXmlBackgroundCmdlet : PowerToolsReadOnlyCmdlet
{
private bool backgroundColor;
private bool backgroundImage;
private string outputFolder;
#region Parameters
[Parameter(Position = 1,
Mandatory = false,
ValueFromPipeline = false,
HelpMessage = "Path of folder to store result documents")
]
public string OutputFolder
{
get
{
return outputFolder;
}
set
{
outputFolder = SessionState.Path.Combine(SessionState.Path.CurrentLocation.Path, value);
}
}
[Parameter(
Mandatory = false,
HelpMessage = "Gets the image from the background.")
]
[ValidateNotNullOrEmpty]
public SwitchParameter Image
{
get
{
return backgroundImage;
}
set
{
backgroundImage = value;
}
}
[Parameter(
Mandatory = false,
HelpMessage = "Gets the color of the background (hexadecimal format)")
]
[ValidateNotNullOrEmpty]
public SwitchParameter Color
{
get
{
return backgroundColor;
}
set
{
backgroundColor = value;
}
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
if (backgroundColor || backgroundImage)
{
foreach (var document in AllDocuments("Get-OpenXmlBackground"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
string bgColor = string.Empty;
string bgImagePath = string.Empty;
if (backgroundColor)
{
bgColor = BackgroundAccessor.GetBackgroundColor((WmlDocument)document);
if (bgColor != "")
WriteObject(System.Drawing.Color.FromArgb(Convert.ToInt32(bgColor, 16)), true);
}
else if (backgroundImage)
{
string filename = BackgroundAccessor.GetImageFileName((WmlDocument)document);
if (filename != "")
{
string target = filename;
if (OutputFolder != null)
{
FileInfo temp = new FileInfo(filename);
target = OutputFolder + "\\" + temp.Name;
}
if (!File.Exists(target) || ShouldProcess(target, "Get-OpenXmlBackground"))
{
BackgroundAccessor.SaveImageToFile((WmlDocument)document, target);
System.IO.FileInfo fileInfo = new System.IO.FileInfo(filename);
WriteObject(fileInfo, true);
}
}
}
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
else
WriteError(new ErrorRecord(new ArgumentException("Requires one of the two switches: Color or Image."), "OpenXmlPowerToolsError", ErrorCategory.InvalidArgument, null));
}
#endregion
}
}

View File

@@ -0,0 +1,40 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
[Cmdlet(VerbsCommon.Get, "OpenXmlComment")]
public class GetOpenXmlCommentCmdlet : PowerToolsReadOnlyCmdlet
{
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Get-OpenXmlComment"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
object comments = CommentAccessor.GetAllComments((WmlDocument)document, CommentFormat.Xml);
WriteObject(comments, true);
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,70 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Get-OpenXmlCustomXmlData cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Get, "OpenXmlCustomXmlData")]
[OutputType("XDocument")]
public class GetOpenXmlCustomXmlData : PowerToolsReadOnlyCmdlet
{
#region Parameters
string xmlPartName;
/// <summary>
/// Part parameter
/// </summary>
[Parameter(
Position = 1,
Mandatory = true,
HelpMessage = "Custom Xml part name")
]
[ValidateNotNullOrEmpty]
public string Part
{
get
{
return xmlPartName;
}
set
{
xmlPartName = value;
}
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Get-OpenXmlCustomXmlData"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
WriteObject(CustomXmlAccessor.Find((WmlDocument)document, xmlPartName), true);
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,43 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Gets a summary of digital signatures present inside a document
/// </summary>
[Cmdlet(VerbsCommon.Get, "OpenXmlDigitalSignature")]
[OutputType("string")]
public class GetOpenXmlDigitalSignatureCmdlet : PowerToolsReadOnlyCmdlet
{
#region Cmdlet Overrides
/// <summary>
/// Entry point for Power Shell Cmdlets
/// </summary>
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Get-OpenXmlDigitalSignature"))
{
try
{
WriteObject(DigitalSignatureAccessor.GetList(document), true);
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,41 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Get-OpenXmlDocument Cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Get, "OpenXmlDocument")]
[OutputType("OpenXmlPowerToolsDocument")]
public class GetOpenXmlDocumentCmdlet : PowerToolsReadOnlyCmdlet
{
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Get-OpenXmlCustomXmlData"))
{
try
{
WriteObject(new OpenXmlPowerToolsDocument(document), true);
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,77 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Get the footer files of a word document
/// </summary>
[Cmdlet(VerbsCommon.Get, "OpenXmlFooter")]
[OutputType("XDocument")]
public class GetOpenXmlFooter : PowerToolsReadOnlyCmdlet
{
#region Parameters
private FooterType footerType;
/// <summary>
/// FooterType parameter
/// </summary>
[Parameter(Position = 1,
Mandatory = false,
HelpMessage = "Specifies the type of the footer to extract.")
]
public FooterType FooterType
{
get
{
return footerType;
}
set
{
footerType = value;
}
}
[Parameter(Position = 2,
Mandatory = false,
HelpMessage = "Number of section")
]
public int Section = 1;
# endregion
#region Cmdlet Overrides
/// <summary>
/// Entry point for PowerShell commandlets
/// </summary>
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Get-OpenXmlFooter"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
WriteObject(FooterAccessor.GetFooter((WmlDocument)document, footerType, Section - 1), true);
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,74 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Get the header files of a word document
/// </summary>
[Cmdlet(VerbsCommon.Get, "OpenXmlHeader")]
[OutputType("XDocument")]
public class GetOpenXmlHeader : PowerToolsReadOnlyCmdlet
{
#region Parameters
private HeaderType headerType;
[Parameter(Position = 1,
Mandatory = false,
HelpMessage = "Specifies the type of the header to extract.")
]
public HeaderType HeaderType
{
get
{
return headerType;
}
set
{
headerType = value;
}
}
[Parameter(Position = 2,
Mandatory = false,
HelpMessage = "Number of section")
]
public int Section = 1;
# endregion
#region Cmdlet Overrides
/// <summary>
/// Entry point for PowerShell cmdlets
/// </summary>
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Get-OpenXmlHeader"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
WriteObject(HeaderAccessor.GetHeader((WmlDocument)document, headerType, Section - 1), true);
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,43 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Gets the style.xml of a word document
/// </summary>
[Cmdlet(VerbsCommon.Get, "OpenXmlStyle")]
[OutputType("XDocument")]
public class GetOpenXmlStyleCmdlet : PowerToolsReadOnlyCmdlet
{
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Get-OpenXmlStyle"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
WriteObject(StyleAccessor.GetStylesDocument((WmlDocument)document), true);
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,65 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Get-OpenXmlTheme cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Get, "OpenXmlTheme")]
[OutputType("OpenXmlPowerToolsDocument")]
public class GetOpenXmlThemeCmdlet : PowerToolsReadOnlyCmdlet
{
#region Parameters
[Parameter(
Mandatory = false,
HelpMessage = "Use this switch to pipe out the extracted theme.")
]
public SwitchParameter PassThru;
[Parameter(Position = 1,
Mandatory = false,
ValueFromPipeline = false,
HelpMessage = "Path of folder to store result documents")
]
[ValidateNotNullOrEmpty]
public string OutputPath;
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Get-OpenXmlTheme"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OpenXmlPowerToolsDocument theme = ThemeAccessor.GetTheme((WmlDocument)document);
if (OutputPath != null)
theme.SaveAs(System.IO.Path.Combine(SessionState.Path.CurrentLocation.Path, OutputPath));
if (PassThru || OutputPath == null)
WriteObject(theme, true);
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,46 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Gets the text of a watermark in a document.
/// </summary>
[Cmdlet(VerbsCommon.Get, "OpenXmlWatermark")]
[OutputType("string")]
public class GetOpenXmlWatermarkCmdlet : PowerToolsReadOnlyCmdlet
{
#region Cmdlet Overrides
/// <summary>
/// Entry point for PowerShell cmdlets
/// </summary>
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Get-OpenXmlWatermark"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
WriteObject(WatermarkAccessor.GetWatermarkText((WmlDocument)document), true);
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,41 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools.Commands
{
[Cmdlet(VerbsCommon.Lock, "OpenXmlDocument", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class LockOpenXmlDocumentCmdlet : PowerToolsModifierCmdlet
{
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Lock-OpenXmlDocument"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(PowerToolsExtensions.Lock((WmlDocument)document));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,264 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.IO;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Collections.Generic;
namespace OpenXmlPowerTools
{
/// <summary>
/// Specify the entire source document
/// </summary>
public class DocumentSource
{
/// <summary>
/// Full or relative path name for the file
/// </summary>
public string SourceFile;
/// <summary>
/// Starting paragraph number (1 is the first paragraph)
/// </summary>
public int Start;
/// <summary>
/// Number of paragraphs
/// </summary>
public int Count;
/// <summary>
/// True, if you want to keep the section at the end of the document
/// </summary>
public bool KeepSection;
/// <summary>
/// Specify the entire source document
/// </summary>
public DocumentSource(string source)
{
SourceFile = source;
Start = -1;
Count = -1;
}
/// <summary>
/// Specify from "start" to the end of the document
/// </summary>
public DocumentSource(string source, int start)
{
SourceFile = source;
Start = start;
Count = -1;
}
/// <summary>
/// Specify from "start" and include "count" number of paragraphs
/// </summary>
public DocumentSource(string source, int start, int count)
{
SourceFile = source;
Start = start;
Count = count;
}
}
}
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Transform-OpenXmlToHtml cmdlet
/// </summary>
[Cmdlet(VerbsData.Merge, "OpenXmlDocument", SupportsShouldProcess = true)]
public class MergeOpenXmlDocumentCmdlet : PowerToolsReadOnlyCmdlet
{
private DocumentSource[] m_Sources;
private string m_OutputPath = "";
private int m_Start = 1;
private int m_Count = -1;
private bool m_KeepSections = false;
private List<Source> buildSources = new List<Source>();
#region Parameters
/// <summary>
/// OutputPath parameter
/// </summary>
[Parameter(
Position = 1,
Mandatory = true,
HelpMessage = "Path of file for output document")
]
public string OutputPath
{
get
{
return m_OutputPath;
}
set
{
m_OutputPath = System.IO.Path.Combine(SessionState.Path.CurrentLocation.Path, value);
}
}
/// <summary>
/// Start parameter
/// </summary>
[Parameter(
Mandatory = false,
HelpMessage = "Starting paragraph number to extract")
]
public int Start
{
get
{
return m_Start;
}
set
{
m_Start = value;
}
}
/// <summary>
/// Count parameter
/// </summary>
[Parameter(
Mandatory = false,
HelpMessage = "Number of paragraphs to extract")
]
public int Count
{
get
{
return m_Count;
}
set
{
m_Count = value;
}
}
/// <summary>
/// Sources parameter
/// </summary>
[Parameter(
Mandatory = false,
HelpMessage = "Array of sources to extract")
]
public DocumentSource[] Sources
{
get
{
return m_Sources;
}
set
{
m_Sources = value;
}
}
/// <summary>
/// KeepSections parameter
/// </summary>
[Parameter(
Mandatory = false,
HelpMessage = "Keep a section break between each merged document.")
]
[ValidateNotNullOrEmpty]
public SwitchParameter KeepSections
{
get
{
return m_KeepSections;
}
set
{
m_KeepSections = value;
}
}
[Parameter(
Mandatory = false,
HelpMessage = "Use this switch to pipe out the processed documents.")
]
[ValidateNotNullOrEmpty]
public SwitchParameter PassThru;
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Merge-OpenXmlDocumentCmdlet"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
if (m_Count != -1)
buildSources.Add(new Source((WmlDocument)document, m_Start - 1, m_Count, m_KeepSections));
else
buildSources.Add(new Source((WmlDocument)document, m_Start - 1, m_KeepSections));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
protected override void EndProcessing()
{
try
{
if (m_Sources != null)
{
foreach (DocumentSource source in m_Sources)
{
Collection<PathInfo> fileList = SessionState.Path.GetResolvedPSPathFromPSPath(source.SourceFile);
foreach (var file in fileList)
{
OpenXmlPowerToolsDocument document = OpenXmlPowerToolsDocument.FromFileName(file.Path);
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
if (source.Count != -1)
buildSources.Add(new Source((WmlDocument)document, source.Start - 1, source.Count, source.KeepSection));
else if (source.Start != -1)
buildSources.Add(new Source((WmlDocument)document, source.Start - 1, source.KeepSection));
else
buildSources.Add(new Source((WmlDocument)document, source.KeepSection));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
}
WmlDocument result = DocumentBuilder.BuildDocument(buildSources);
if (m_OutputPath != null)
{
if (!File.Exists(m_OutputPath) || ShouldProcess(m_OutputPath, "Merge-OpenXmlDocumentCmdlet"))
result.SaveAs(m_OutputPath);
}
if (PassThru)
WriteObject(result, true);
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, null));
}
}
#endregion
}
}

View File

@@ -0,0 +1,95 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.IO;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Collections.Generic;
namespace OpenXmlPowerTools.Commands
{
[Cmdlet(VerbsData.Merge, "OpenXmlDocumentComment", SupportsShouldProcess = true)]
public class MergeOpenXmlDocumentCommentCmdlet : PowerToolsReadOnlyCmdlet
{
private string m_OutputPath = "";
private WmlDocument current;
#region Parameters
[Parameter(
Position = 1,
Mandatory = true,
HelpMessage = "Path of file for output document")
]
public string OutputPath
{
get
{
return m_OutputPath;
}
set
{
m_OutputPath = System.IO.Path.Combine(SessionState.Path.CurrentLocation.Path, value);
}
}
[Parameter(
Mandatory = false,
HelpMessage = "Use this switch to pipe out the processed document.")
]
public SwitchParameter PassThru;
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Merge-OpenXmlDocumentCommentCmdlet"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
if (current == null)
current = (WmlDocument)document;
else
current = CommentMerger.MergeComments(current, (WmlDocument)document);
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
protected override void EndProcessing()
{
try
{
if (m_OutputPath != null)
{
if (!File.Exists(m_OutputPath) || ShouldProcess(m_OutputPath, "Merge-OpenXmlDocumentCommentCmdlet"))
current.SaveAs(m_OutputPath);
}
if (PassThru)
WriteObject(current, true);
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, null));
}
}
#endregion
}
}

View File

@@ -0,0 +1,331 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.IO;
using System.Xml;
using System.Collections.ObjectModel;
namespace OpenXmlPowerTools.Commands
{
public class PowerToolsReadOnlyCmdlet : PSCmdlet
{
private OpenXmlPowerToolsDocument[] documents;
internal string[] fileNameReferences;
#region Parameters
/// <summary>
/// Specify the Document parameter
/// </summary>
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "Specifies the documents to be processed.")]
public OpenXmlPowerToolsDocument[] Document
{
get
{
return documents;
}
set
{
documents = value;
}
}
/// <summary>
/// Specify the Path parameter
/// </summary>
[Parameter(Position = 0,
Mandatory = false,
HelpMessage = "Specifies the path to the documents to be processed")]
[ValidateNotNullOrEmpty]
public string[] Path
{
set
{
fileNameReferences = value;
}
}
#endregion
internal IEnumerable<OpenXmlPowerToolsDocument> AllDocuments(string action)
{
if (fileNameReferences != null)
{
foreach (var path in fileNameReferences)
{
Collection<PathInfo> fileList;
try
{
fileList = SessionState.Path.GetResolvedPSPathFromPSPath(path);
}
catch (ItemNotFoundException e)
{
WriteError(new ErrorRecord(e, "OpenXmlPowerToolsError", ErrorCategory.OpenError, path));
continue;
}
foreach (var file in fileList)
{
OpenXmlPowerToolsDocument document;
try
{
document = OpenXmlPowerToolsDocument.FromFileName(file.Path);
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "OpenXmlPowerToolsError", ErrorCategory.OpenError, file));
continue;
}
yield return document;
}
}
}
else if (Document != null)
{
foreach (OpenXmlPowerToolsDocument document in Document)
{
OpenXmlPowerToolsDocument specificDoc;
try
{
specificDoc = OpenXmlPowerToolsDocument.FromDocument(document);
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "OpenXmlPowerToolsError", ErrorCategory.InvalidType, document));
continue;
}
yield return specificDoc;
}
}
}
}
public class PowerToolsModifierCmdlet : PSCmdlet
{
private OpenXmlPowerToolsDocument[] documents;
internal string[] fileNameReferences;
protected bool passThru = false;
private string outputFolder;
#region Parameters
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "Specifies the documents to be processed.")]
public OpenXmlPowerToolsDocument[] Document
{
get
{
return documents;
}
set
{
documents = value;
}
}
[Parameter(Position = 0,
Mandatory = false,
HelpMessage = "Specifies the path to the documents to be processed")]
[ValidateNotNullOrEmpty]
public string[] Path
{
set
{
fileNameReferences = value;
}
}
[Parameter(Position = 1,
Mandatory = false,
ValueFromPipeline = false,
HelpMessage = "Path of folder to store result documents")
]
public string OutputFolder
{
get
{
return outputFolder;
}
set
{
outputFolder = SessionState.Path.Combine(SessionState.Path.CurrentLocation.Path, value);
}
}
[Parameter(
Mandatory = false,
HelpMessage = "Use this switch to pipe out the processed documents.")
]
[ValidateNotNullOrEmpty]
public SwitchParameter PassThru
{
get
{
return passThru;
}
set
{
passThru = value;
}
}
#endregion
internal IEnumerable<OpenXmlPowerToolsDocument> AllDocuments(string action)
{
if (fileNameReferences != null)
{
foreach (var path in fileNameReferences)
{
Collection<PathInfo> fileList;
try
{
fileList = SessionState.Path.GetResolvedPSPathFromPSPath(path);
}
catch (ItemNotFoundException e)
{
WriteError(new ErrorRecord(e, "OpenXmlPowerToolsError", ErrorCategory.OpenError, path));
continue;
}
foreach (var file in fileList)
{
string target = file.Path;
if (OutputFolder != null)
{
FileInfo temp = new FileInfo(file.Path);
target = OutputFolder + "\\" + temp.Name;
}
if (!File.Exists(target) || ShouldProcess(target, action))
{
OpenXmlPowerToolsDocument document;
try
{
document = OpenXmlPowerToolsDocument.FromFileName(file.Path);
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "OpenXmlPowerToolsError", ErrorCategory.OpenError, file));
continue;
}
yield return document;
}
}
}
}
else if (Document != null)
{
foreach (OpenXmlPowerToolsDocument document in Document)
{
string target = document.FileName;
if (OutputFolder != null)
{
FileInfo temp = new FileInfo(document.FileName);
target = OutputFolder + "\\" + temp.Name;
}
if (!File.Exists(target) || ShouldProcess(target, action))
{
OpenXmlPowerToolsDocument specificDoc;
try
{
specificDoc = OpenXmlPowerToolsDocument.FromDocument(document);
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "OpenXmlPowerToolsError", ErrorCategory.InvalidType, document));
continue;
}
yield return specificDoc;
}
}
}
}
// Determines if and where to write the modified document
internal void OutputDocument(OpenXmlPowerToolsDocument doc)
{
if (OutputFolder != null)
{
FileInfo file = new FileInfo(doc.FileName);
string newName = OutputFolder + "\\" + file.Name;
doc.SaveAs(newName);
}
else if (!PassThru)
doc.Save();
if (PassThru)
WriteObject(doc, true);
}
}
public class PowerToolsCreateCmdlet : PSCmdlet
{
protected bool passThru = false;
#region Parameters
/// <summary>
/// PassThru parameter
/// </summary>
[Parameter(
Mandatory = false,
HelpMessage = "Use this switch to pipe out the processed documents.")
]
[ValidateNotNullOrEmpty]
public SwitchParameter PassThru
{
get
{
return passThru;
}
set
{
passThru = value;
}
}
#endregion
// Determines if and where to write the modified document
internal void OutputDocument(OpenXmlPowerToolsDocument doc)
{
if (PassThru)
WriteObject(doc, true);
else
doc.Save();
}
}
public static class PowerToolsExceptionHandling
{
public static ErrorRecord GetExceptionErrorRecord(Exception e, OpenXmlPowerToolsDocument doc)
{
ErrorCategory cat = ErrorCategory.NotSpecified;
if (e is ArgumentException)
cat = ErrorCategory.InvalidArgument;
else if (e is InvalidOperationException)
cat = ErrorCategory.InvalidOperation;
else if (e is PowerToolsDocumentException)
cat = ErrorCategory.OpenError;
else if (e is PowerToolsInvalidDataException || e is XmlException)
cat = ErrorCategory.InvalidData;
return new ErrorRecord(e, (cat == ErrorCategory.NotSpecified) ? "General" : "OpenXmlPowerToolsError", cat, doc);
}
}
}

View File

@@ -0,0 +1,43 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Remove-OpenXmlComment cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Remove, "OpenXmlComment", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class RemoveOpenXmlCommentCmdlet : PowerToolsModifierCmdlet
{
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Remove-OpenXmlComment"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(CommentAccessor.RemoveAll((WmlDocument)document));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,44 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Remove-OpenXmlDigitalSignature cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Remove, "OpenXmlDigitalSignature", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class RemoveOpenXmlDigitalSignaturesCmdlet : PowerToolsModifierCmdlet
{
#region Cmdlet Overrides
/// <summary>
/// Entry point for PowerShell cmdlets
/// </summary>
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Remove-OpenXmlDigitalSignature"))
{
try
{
OutputDocument(DigitalSignatureAccessor.RemoveAll(document));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,156 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
[Cmdlet(VerbsCommon.Remove, "OpenXmlMarkup", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class RemoveOpenXmlMarkupCmdlet : PowerToolsModifierCmdlet
{
private SimplifyMarkupSettings settings = new SimplifyMarkupSettings();
#region Parameters
[Parameter(Mandatory = false)]
public SwitchParameter AcceptRevisions
{
get { return settings.AcceptRevisions; }
set { settings.AcceptRevisions = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter RemoveContentControls
{
get { return settings.RemoveContentControls; }
set { settings.RemoveContentControls = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter RemoveSmartTags
{
get { return settings.RemoveSmartTags; }
set { settings.RemoveSmartTags = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter RemoveRsidInfo
{
get { return settings.RemoveRsidInfo; }
set { settings.RemoveRsidInfo = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter RemoveComments
{
get { return settings.RemoveComments; }
set { settings.RemoveComments = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter RemoveEndAndFootNotes
{
get { return settings.RemoveEndAndFootNotes; }
set { settings.RemoveEndAndFootNotes = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter ReplaceTabsWithSpaces
{
get { return settings.ReplaceTabsWithSpaces; }
set { settings.ReplaceTabsWithSpaces = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter RemoveFieldCodes
{
get { return settings.RemoveFieldCodes; }
set { settings.RemoveFieldCodes = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter RemovePermissions
{
get { return settings.RemovePermissions; }
set { settings.RemovePermissions = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter RemoveProof
{
get { return settings.RemoveProof; }
set { settings.RemoveProof = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter RemoveSoftHyphens
{
get { return settings.RemoveSoftHyphens; }
set { settings.RemoveSoftHyphens = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter RemoveLastRenderedPageBreak
{
get { return settings.RemoveLastRenderedPageBreak; }
set { settings.RemoveLastRenderedPageBreak = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter RemoveBookmarks
{
get { return settings.RemoveBookmarks; }
set { settings.RemoveBookmarks = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter RemoveWebHidden
{
get { return settings.RemoveWebHidden; }
set { settings.RemoveWebHidden = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter RemoveGoBackBookmark
{
get { return settings.RemoveGoBackBookmark; }
set { settings.RemoveGoBackBookmark = value; }
}
[Parameter(Mandatory = false)]
public SwitchParameter NormalizeXml
{
get { return settings.NormalizeXml; }
set { settings.NormalizeXml = value; }
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Remove-OpenXmlMarkup"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(MarkupSimplifier.SimplifyMarkup((WmlDocument)document, settings));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,46 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Remove-OpenXmlPersonalInformation cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Remove, "OpenXmlPersonalInformation", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class RemoveOpenXmlPersonalInformationCmdlet : PowerToolsModifierCmdlet
{
#region Cmdlet Overrides
/// <summary>
/// Entry point for PowerShell cmdlets
/// </summary>
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Remove-OpenXmlPersonalInformationCmdlet"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(PowerToolsExtensions.RemovePersonalInformation((WmlDocument)document));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,213 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.IO;
using System.Collections.Generic;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Match information for Select-OpenXmlString
/// </summary>
public class MatchInfo
{
/// <summary>
/// Full path of file that matched
/// </summary>
public string Path { get; set; }
/// <summary>
/// Filename of file that matched
/// </summary>
public string Filename
{
get
{
if (Path == null)
return null;
FileInfo info = new FileInfo(Path);
return info.Name;
}
}
/// <summary>
/// Element number of element whose style or content matched
/// </summary>
public int ElementNumber { get; set; }
/// <summary>
/// Full contents, without formatting, of matched element
/// </summary>
public string Content { get; set; }
/// <summary>
/// The first style that matched the element
/// </summary>
public string Style { get; set; }
/// <summary>
/// The first pattern that matched the content of the element
/// </summary>
public string Pattern { get; set; }
/// <summary>
/// Indicates if case was ignored on the pattern match
/// </summary>
public bool IgnoreCase { get; set; }
/// <summary>
/// Simple constructor
/// </summary>
public MatchInfo()
{
}
}
/// <summary>
/// Get the footer files of a word document
/// </summary>
[Cmdlet(VerbsCommon.Select, "OpenXmlString")]
[OutputType("MatchInfo")]
public class SelectOpenXmlString : PowerToolsReadOnlyCmdlet
{
private string[] m_StyleSearch;
private string[] m_TextSearch;
private bool m_SimpleMatch = false;
private bool m_CaseSensitive = false;
private bool m_List = false;
/// <summary>
/// A list of text strings to match.
/// </summary>
[Parameter(Position = 1,
Mandatory = false,
HelpMessage = "Specifies the a list of text strings to match.")
]
public string[] Pattern
{
get
{
return m_TextSearch;
}
set
{
m_TextSearch = value;
}
}
/// <summary>
/// A list of style names to match.
/// </summary>
[Parameter(
Mandatory = false,
HelpMessage = "Specifies the a list of style names to match.")
]
public string[] Style
{
get
{
return m_StyleSearch;
}
set
{
m_StyleSearch = value;
}
}
/// <summary>
/// simpleMatch parameter
/// </summary>
[Parameter(
Mandatory = false,
HelpMessage = "Specifies that a simple match, rather than a regular expression match, should be used.")
]
[ValidateNotNullOrEmpty]
public SwitchParameter simpleMatch
{
get
{
return m_SimpleMatch;
}
set
{
m_SimpleMatch = value;
}
}
/// <summary>
/// caseSensitive parameter
/// </summary>
[Parameter(
Mandatory = false,
HelpMessage = "Makes matches case sensitive. By default, matching is not case sensitive.")
]
[ValidateNotNullOrEmpty]
public SwitchParameter caseSensitive
{
get
{
return m_CaseSensitive;
}
set
{
m_CaseSensitive = value;
}
}
/// <summary>
/// list parameter
/// </summary>
[Parameter(
Mandatory = false,
HelpMessage = "Specifies that only one match should result for each input file. The returned MatchInfo objects only include information about that first match.")
]
[ValidateNotNullOrEmpty]
public SwitchParameter list
{
get
{
return m_List;
}
set
{
m_List = value;
}
}
/// <summary>
/// Entry point for PowerShell commandlets
/// </summary>
protected override void ProcessRecord()
{
List<MatchInfo> results = new List<MatchInfo>();
foreach (var document in AllDocuments("Select-OpenXmlString"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
MatchInfo[] result = PowerToolsExtensions.SearchInDocument((WmlDocument)document, m_StyleSearch, m_TextSearch, !m_SimpleMatch, !m_CaseSensitive);
if (!m_List)
foreach (MatchInfo item in result)
{
item.Path = document.FileName;
results.Add(item);
}
else if (result.GetUpperBound(0) >= 0)
{
result[0].Path = document.FileName;
results.Add(result[0]);
}
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
WriteObject(results, true);
}
}
}
}

View File

@@ -0,0 +1,159 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Linq;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Set-OpenXmlBackground cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Set, "OpenXmlBackground", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class SetOpenXmlBackgroundCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
private string backgroundColor;
private string backgroundImagePath;
/// <summary>
/// ImagePath parameter
/// </summary>
[Parameter(
Mandatory = false,
HelpMessage = "Path of image to set as document background")
]
[ValidateNotNullOrEmpty]
public string ImagePath
{
get
{
return backgroundImagePath;
}
set
{
backgroundImagePath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path;
}
}
/// <summary>
/// ColorName parameter
/// </summary>
[Parameter(
Mandatory = false,
HelpMessage = "Color code (hexadecimal) to set as the document background")
]
[ValidateNotNullOrEmpty]
public string ColorName
{
get
{
return backgroundColor;
}
set
{
backgroundColor = value;
}
}
/// <summary>
/// Color parameter
/// </summary>
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "Color object to set as the document background")
]
[ValidateNotNullOrEmpty]
public System.Drawing.Color Color
{
get
{
return System.Drawing.Color.FromArgb(backgroundColor == null ? 0 : Convert.ToInt32(backgroundColor,16));
}
set
{
backgroundColor = String.Format("{0:X2}{1:X2}{2:X2}", value.R, value.G, value.B);
}
}
/// <summary>
/// ImageFile parameter
/// </summary>
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
HelpMessage = "Image object to use as document background")
]
[ValidateNotNullOrEmpty]
public System.IO.FileInfo ImageFile
{
get
{
return new System.IO.FileInfo(backgroundImagePath == null ? "." : backgroundImagePath);
}
set
{
backgroundImagePath = value.FullName;
}
}
#endregion
#region Cmdlet Overrides
/// <summary>
/// Entry point for PowerShell cmdlets
/// </summary>
protected override void ProcessRecord()
{
// If an image was piped in, the background color string will not be valid.
if (backgroundImagePath != null)
backgroundColor = null;
// At least one of the backgroundColor or backgroundImage parameters must be set it
if (backgroundColor == null && backgroundImagePath == null)
{
WriteError(new ErrorRecord(new ArgumentException("Requires at least one of the three parameters: Color, Image or ImagePath."), "OpenXmlPowerTools", ErrorCategory.InvalidArgument, null));
return;
}
foreach (var document in AllDocuments("Set-OpenXmlBackground"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
if (backgroundImagePath != null)
{
// Open as image to verify that it is valid
System.Drawing.Image.FromFile(backgroundImagePath);
OutputDocument(BackgroundAccessor.SetImage((WmlDocument)document, backgroundImagePath));
}
else
{
// Validate color value
System.Drawing.Color.FromArgb(Convert.ToInt32(backgroundColor, 16));
OutputDocument(BackgroundAccessor.SetColor((WmlDocument)document, backgroundColor));
}
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,88 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Set-OpenXmlContentFormat cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Set, "OpenXmlContentFormat", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class SetOpenXmlContentFormat : PowerToolsModifierCmdlet
{
#region Parameters
private string xpathInsertionPoint;
private string xmlContent;
/// <summary>
/// InsertionPoint parameter
/// </summary>
[Parameter(Position = 2,
Mandatory = true,
HelpMessage = "Insertion point location")]
[ValidateNotNullOrEmpty]
public string InsertionPoint
{
get
{
return xpathInsertionPoint;
}
set
{
xpathInsertionPoint = value;
}
}
/// <summary>
/// Content parameter
/// </summary>
[Parameter(Position = 3,
Mandatory = true,
HelpMessage = "Xml to insert")]
[ValidateNotNullOrEmpty]
public string Content
{
get
{
return xmlContent;
}
set
{
xmlContent = value;
}
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Set-OpenXmlContentFormat"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(ContentFormatAccessor.Insert((WmlDocument)document, xpathInsertionPoint, xmlContent));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,141 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Linq;
using System.Xml.Linq;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Set-OpenXmlContentStyle cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Set, "OpenXmlContentStyle", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class SetOpenXmlContentStyle : PowerToolsModifierCmdlet
{
#region Parameters
private string xpathInsertionPoint;
private string stylesSourcePath;
private XDocument stylesSource;
private string styleName;
/// <summary>
/// InsertionPoint parameter
/// </summary>
[Parameter(Position = 2,
Mandatory = true,
HelpMessage = "Insertion point location")]
[ValidateNotNullOrEmpty]
public string InsertionPoint
{
get
{
return xpathInsertionPoint;
}
set
{
xpathInsertionPoint = value;
}
}
/// <summary>
/// StyleName parameter
/// </summary>
[Parameter(Position = 3,
Mandatory = true,
HelpMessage = "Style name")]
[ValidateNotNullOrEmpty]
public string StyleName
{
get
{
return styleName;
}
set
{
styleName = value;
}
}
/// <summary>
/// StylesSourcePath parameter
/// </summary>
[Parameter(Position = 4,
Mandatory = false,
HelpMessage = "Style file path")]
[ValidateNotNullOrEmpty]
public string StylesSourcePath
{
get
{
return stylesSourcePath;
}
set
{
stylesSourcePath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path;
}
}
/// <summary>
/// StylesSource parameter
/// </summary>
[Parameter(Position = 5,
Mandatory = false,
ValueFromPipeline = true,
HelpMessage = "Styles from XDocument")]
[ValidateNotNullOrEmpty]
public XDocument StylesSource
{
get
{
return stylesSource;
}
set
{
stylesSource = value;
}
}
#endregion
#region Cmdlet Overrides
/// <summary>
/// Entry point for PowerShell cmdlets
/// </summary>
protected override void ProcessRecord()
{
if (stylesSourcePath != null)
stylesSource = XDocument.Load(stylesSourcePath);
if (stylesSource == null)
{
WriteError(new ErrorRecord(new Exception("No styles source was specified."), "BadParameters", ErrorCategory.InvalidArgument, null));
return;
}
foreach (var document in AllDocuments("Set-OpenXmlContentStyle"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(StyleAccessor.Insert((WmlDocument)document, xpathInsertionPoint, styleName, stylesSource));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,126 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Linq;
using System.Xml.Linq;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Set-OpenXmlCustomXmlData cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Set, "OpenXmlCustomXmlData", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class SetOpenXmlCustomXmlDataCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
private string xmlPath;
private string partName;
private XDocument customData;
/// <summary>
/// Specify the CustomXmlPart parameter
/// </summary>
[Parameter(Position = 2,
Mandatory = false,
HelpMessage = "Custom Xml part path")]
[ValidateNotNullOrEmpty]
public string PartPath
{
get
{
return xmlPath;
}
set
{
var xmlPartFileNames = SessionState.Path.GetResolvedPSPathFromPSPath(value);
if (xmlPartFileNames.Count() == 1)
{
xmlPath = xmlPartFileNames.First().Path;
}
else if (xmlPartFileNames.Count() > 1)
{
throw new Exception("Too many xmlParts specified.");
}
}
}
/// <summary>
/// Specify the CustomXmlPart parameter
/// </summary>
[Parameter(Position = 3,
Mandatory = false,
HelpMessage = "Name for the new custom part")]
[ValidateNotNullOrEmpty]
public string PartName
{
get
{
return partName;
}
set
{
partName = value;
}
}
/// <summary>
/// Specify the CustomXmlPart parameter
/// </summary>
[Parameter(Position = 4,
Mandatory = false,
ValueFromPipeline = true,
HelpMessage = "Custom Xml document")]
[ValidateNotNullOrEmpty]
public XDocument Part
{
get
{
return customData;
}
set
{
customData = value;
}
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
if (xmlPath != null)
{
customData = XDocument.Load(xmlPath);
if (partName == null)
partName = System.IO.Path.GetFileName(xmlPath);
}
foreach (var document in AllDocuments("Set-OpenXmlCustomXmlData"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(CustomXmlAccessor.SetDocument((WmlDocument)document, customData, partName));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,124 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Linq;
using System.Xml.Linq;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Set the footer files of a word document
/// </summary>
[Cmdlet(VerbsCommon.Set, "OpenXmlFooter", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class SetOpenXmlFooterCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
private string footerPath;
private XDocument footer;
private FooterType kind;
[Parameter(Position = 2,
Mandatory = false,
HelpMessage = "The path of the footer to add in the document")
]
[ValidateNotNullOrEmpty]
public string FooterPath
{
get
{
return footerPath;
}
set
{
footerPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path;
}
}
[Parameter(Position = 3,
Mandatory = false,
HelpMessage = "Specify the kind of the footer to extract")
]
public FooterType FooterType
{
get
{
return kind;
}
set
{
kind = value;
}
}
[Parameter(Position = 4,
Mandatory = false,
HelpMessage = "Number of section to modify")
]
public int Section = 1;
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "XDocument of the footer to add")
]
[ValidateNotNullOrEmpty]
public XDocument Footer
{
get
{
return footer;
}
set
{
footer = value;
}
}
#endregion
#region Cmdlet Overrides
/// <summary>
/// Entry point for PowerShell cmdlets
/// </summary>
protected override void ProcessRecord()
{
if (footerPath != null)
footer = XDocument.Load(footerPath);
if (footer == null)
{
WriteError(new ErrorRecord(new ArgumentException("No footer was specified."), "OpenXmlPowerTools", ErrorCategory.InvalidArgument, null));
return;
}
foreach (var document in AllDocuments("Set-OpenXmlFooter"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(FooterAccessor.SetFooter((WmlDocument)document, footer, kind, Section - 1));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,122 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Linq;
using System.Xml.Linq;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Set the header files of a word document
/// </summary>
[Cmdlet(VerbsCommon.Set, "OpenXmlHeader", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class SetOpenXmlHeaderCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
private string headerPath;
private XDocument header;
private HeaderType kind;
[Parameter(Position = 2,
Mandatory = false,
HelpMessage = "The path of the header to add in the document")
]
[ValidateNotNullOrEmpty]
public string HeaderPath
{
get
{
return headerPath;
}
set
{
headerPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path;
}
}
[Parameter(Position = 3,
Mandatory = false,
HelpMessage = "Specify the kind of the header to extract")
]
public HeaderType HeaderType
{
get
{
return kind;
}
set
{
kind = value;
}
}
[Parameter(Position = 4,
Mandatory = false,
HelpMessage = "Number of section to modify")
]
public int Section = 1;
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "XDocument of the header to add")
]
[ValidateNotNullOrEmpty]
public XDocument Header
{
get
{
return header;
}
set
{
header = value;
}
}
#endregion
#region Cmdlet Overrides
/// <summary>
/// Entry point for PowerShell cmdlets
/// </summary>
protected override void ProcessRecord()
{
if (headerPath != null)
header = XDocument.Load(headerPath);
if (header == null)
{
WriteError(new ErrorRecord(new ArgumentException("No footer was specified."), "OpenXmlPowerTools", ErrorCategory.InvalidArgument, null));
return;
}
foreach (var document in AllDocuments("Set-OpenXmlHeader"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(HeaderAccessor.SetHeader((WmlDocument)document, header, kind, Section - 1));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,203 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Cmdlet class for setting a cell style in a SpreadsheetML document
/// </summary>
[Cmdlet(VerbsCommon.Set, "OpenXmlSpreadSheetCellStyle", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class SetOpenXmlSpreadSheetCellStyleCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
private int fromRow;
private int toRow;
private short fromColumn;
private short toColumn;
private string cellStyle;
private string worksheetName;
/// <summary>
/// Initial row for start setting the value
/// </summary>
[Parameter(Position = 2,
Mandatory = true,
HelpMessage = "Initial row for start setting the cell style")]
[ValidateNotNullOrEmpty]
public int FromRow
{
get
{
return fromRow;
}
set
{
if (value > 0)
{
fromRow = value;
}
else
{
new System.Management.Automation.ParameterBindingException("Initial row must be greater than zero");
}
}
}
/// <summary>
/// Initial row for start setting the value
/// </summary>
[Parameter(Position = 3,
Mandatory = true,
HelpMessage = "Final row for start setting the cell style")]
[ValidateNotNullOrEmpty]
public int ToRow
{
get
{
return toRow;
}
set
{
if (value > 0)
{
toRow = value;
}
else
{
new System.Management.Automation.ParameterBindingException("Final row must be greater than zero");
}
}
}
/// <summary>
/// Initial column for start setting the value
/// </summary>
[Parameter(Position = 4,
Mandatory = true,
HelpMessage = "Initial column for start setting the cell style")]
[ValidateNotNullOrEmpty]
public short FromColumn
{
get
{
return fromColumn;
}
set
{
if (value > 0)
{
fromColumn = value;
}
else
{
new System.Management.Automation.ParameterBindingException("Initial column must be greater than zero");
}
}
}
/// <summary>
/// Final column for start setting the value
/// </summary>
[Parameter(Position = 5,
Mandatory = true,
HelpMessage = "Final column for start setting the cell style")]
[ValidateNotNullOrEmpty]
public short ToColumn
{
get
{
return toColumn;
}
set
{
if (value > 0)
{
toColumn = value;
}
else
{
new System.Management.Automation.ParameterBindingException("Final column must be greater than zero");
}
}
}
/// <summary>
/// Cell Style Name
/// </summary>
[Parameter(Position = 6,
Mandatory = true,
HelpMessage = "Cell Style Name")]
[ValidateNotNullOrEmpty]
public string CellStyle
{
get
{
return cellStyle;
}
set
{
if (value.Trim().Length > 0)
{
cellStyle = value;
}
else
{
throw new ParameterBindingException("CellStyle cannot be empty");
}
}
}
/// <summary>
/// Worksheet name to set the cell value
/// </summary>
[Parameter(Position = 7,
Mandatory = true,
HelpMessage = "Worksheet name to set the cell value")]
[ValidateNotNullOrEmpty]
public string WorksheetName
{
get
{
return worksheetName;
}
set
{
worksheetName = value;
}
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Set-OpenXmlSpreadSheetCellStyle"))
{
try
{
if (!(document is SmlDocument))
throw new PowerToolsDocumentException("Not a spreadsheet document.");
OutputDocument(WorksheetAccessor.SetCellStyle((SmlDocument)document, worksheetName, fromColumn, toColumn, fromRow, toRow, cellStyle));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,195 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Cmdlet for setting a value for a specific cell in a worksheet in a SpreadsheetML document
/// </summary>
[Cmdlet(VerbsCommon.Set, "OpenXmlSpreadSheetCellValue", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class SetOpenXmlSpreadSheetCellValueCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
private int fromRow;
private int toRow;
private short fromColumn;
private short toColumn;
private string _value;
private string worksheetName;
/// <summary>
/// Initial row for start setting the value
/// </summary>
[Parameter(Position = 2,
Mandatory = true,
HelpMessage = "Initial row for start setting the value")]
[ValidateNotNullOrEmpty]
public int FromRow
{
get
{
return fromRow;
}
set
{
if(value >0)
{
fromRow = value;
}
else
{
new System.Management.Automation.ParameterBindingException("Initial row must be greater than zero");
}
}
}
/// <summary>
/// Initial row for start setting the value
/// </summary>
[Parameter(Position = 3,
Mandatory = true,
HelpMessage = "Final row for start setting the value")]
[ValidateNotNullOrEmpty]
public int ToRow
{
get
{
return toRow;
}
set
{
if (value > 0)
{
toRow = value;
}
else
{
new System.Management.Automation.ParameterBindingException("Final row must be greater than zero");
}
}
}
/// <summary>
/// Initial column for start setting the value
/// </summary>
[Parameter(Position = 4,
Mandatory = true,
HelpMessage = "Initial column for start setting the value")]
[ValidateNotNullOrEmpty]
public short FromColumn
{
get
{
return fromColumn;
}
set
{
if (value > 0)
{
fromColumn = value;
}
else
{
new System.Management.Automation.ParameterBindingException("Initial column must be greater than zero");
}
}
}
/// <summary>
/// Final column for start setting the value
/// </summary>
[Parameter(Position = 5,
Mandatory = true,
HelpMessage = "Final column for start setting the value")]
[ValidateNotNullOrEmpty]
public short ToColumn
{
get
{
return toColumn;
}
set
{
if (value > 0)
{
toColumn = value;
}
else
{
new System.Management.Automation.ParameterBindingException("Final column must be greater than zero");
}
}
}
/// <summary>
/// Cell value
/// </summary>
[Parameter(Position = 6,
Mandatory = true,
HelpMessage = "Cell value")]
[ValidateNotNullOrEmpty]
public string Value
{
get
{
return _value;
}
set
{
_value = value;
}
}
/// <summary>
/// Worksheet name to set the cell value
/// </summary>
[Parameter(Position = 7,
Mandatory = true,
HelpMessage = "Worksheet name to set the cell value")]
[ValidateNotNullOrEmpty]
public string WorksheetName
{
get
{
return worksheetName;
}
set
{
worksheetName = value;
}
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Set-OpenXmlSpreadSheetCellValue"))
{
try
{
if (!(document is SmlDocument))
throw new PowerToolsDocumentException("Not a spreadsheet document.");
OutputDocument(WorksheetAccessor.SetCellValue((SmlDocument)document, worksheetName, fromRow, toRow, fromColumn, toColumn, _value));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,142 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Class for setting the width for a range of columns in a worksheet in a SpreadsheetML document
/// </summary>
[Cmdlet(VerbsCommon.Set, "OpenXmlSpreadSheetColumnWidth", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class SetOpenXmlSpreadSheetColumnWidthCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
private short fromColumn;
private short toColumn;
private int width;
private string worksheetName;
/// <summary>
/// Row index for setting value
/// </summary>
[Parameter(Position = 2,
Mandatory = true,
HelpMessage = "Initial Column for Setting Width")]
[ValidateNotNullOrEmpty]
public short FromColumn
{
get
{
return fromColumn;
}
set
{
if (value > 0)
{
fromColumn = value;
}
else
{
new System.Management.Automation.ParameterBindingException("Initial column must be greater than zero");
}
}
}
/// <summary>
/// Column index for setting value
/// </summary>
[Parameter(Position = 3,
Mandatory = true,
HelpMessage = "Final Column for setting width")]
[ValidateNotNullOrEmpty]
public short ToColumn
{
get
{
return toColumn;
}
set
{
if (value > 0)
{
toColumn = value;
}
else
{
new System.Management.Automation.ParameterBindingException("Final Column must be greater than zero");
}
}
}
/// <summary>
/// Cell Style Name
/// </summary>
[Parameter(Position = 4,
Mandatory = true,
HelpMessage = "Column Width")]
[ValidateNotNullOrEmpty]
public int Width
{
get
{
return width;
}
set
{
width = value;
}
}
/// <summary>
/// Worksheet name to set the cell value
/// </summary>
[Parameter(Position = 5,
Mandatory = true,
HelpMessage = "Worksheet name to set the cell value")]
[ValidateNotNullOrEmpty]
public string WorksheetName
{
get
{
return worksheetName;
}
set
{
worksheetName = value;
}
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Set-OpenXmlSpreadSheetColumnWidth"))
{
try
{
if (!(document is SmlDocument))
throw new PowerToolsDocumentException("Not a spreadsheet document.");
OutputDocument(WorksheetAccessor.SetColumnWidth((SmlDocument)document, worksheetName, fromColumn, toColumn, width));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,62 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
[Cmdlet(VerbsCommon.Set, "OpenXmlString", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class SetOpenXmlStringCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
[Parameter(Position = 2,
Mandatory = true,
HelpMessage = "Text to match in document")]
[ValidateNotNullOrEmpty]
public string Pattern;
[Parameter(Position = 3,
Mandatory = true,
HelpMessage = "Text to replace in document")]
[ValidateNotNullOrEmpty]
public string Replace;
[Parameter()]
public SwitchParameter CaseSensitive;
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Set-OpenXmlString"))
{
try
{
if (!(document is WmlDocument) && !(document is PmlDocument))
throw new PowerToolsDocumentException("Not a supported document.");
if (document is WmlDocument)
OutputDocument(TextReplacer.SearchAndReplace((WmlDocument)document, Pattern, Replace, CaseSensitive));
if (document is PmlDocument)
OutputDocument(TextReplacer.SearchAndReplace((PmlDocument)document, Pattern, Replace, CaseSensitive));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,122 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Linq;
using System.Xml.Linq;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Set the style.xml of a word document
/// </summary>
[Cmdlet(VerbsCommon.Set, "OpenXmlStyle", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class SetOpenXmlStyleCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
private string styleFile;
private XDocument stylesDocument;
/// <summary>
/// StylePath parameter
/// </summary>
[Parameter(Position = 2,
Mandatory = false,
HelpMessage = "New Style.xml path")
]
[ValidateNotNullOrEmpty]
public string StylePath
{
get
{
return styleFile;
}
set
{
styleFile = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path;
}
}
/// <summary>
/// Style parameter
/// </summary>
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
HelpMessage = "New styles document")
]
[ValidateNotNullOrEmpty]
public XDocument Style
{
get
{
return stylesDocument;
}
set
{
stylesDocument = value;
}
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
try
{
if (styleFile != null)
stylesDocument = XDocument.Load(styleFile);
if (stylesDocument == null)
{
WriteError(new ErrorRecord(new ArgumentException("No styles document was specified."), "OpenXmlPowerTools", ErrorCategory.InvalidArgument, null));
}
else
{
foreach (var document in AllDocuments("Set-OpenXmlStyle"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(StyleAccessor.SetStylePart((WmlDocument)document, stylesDocument));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
}
catch (ItemNotFoundException e)
{
WriteError(new ErrorRecord(e, "FileNotFound", ErrorCategory.OpenError, null));
}
catch (InvalidOperationException e)
{
WriteError(new ErrorRecord(e, "InvalidOperation", ErrorCategory.InvalidOperation, null));
}
catch (ArgumentException e)
{
WriteError(new ErrorRecord(e, "InvalidArgument", ErrorCategory.InvalidArgument, null));
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "General", ErrorCategory.NotSpecified, null));
}
}
#endregion
}
}

View File

@@ -0,0 +1,99 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Linq;
using System.IO.Packaging;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Set-OpenXmlTheme cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Set, "OpenXmlTheme", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class SetOpenXmlThemeCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
private string themePath;
private OpenXmlPowerToolsDocument themePackage;
/// <summary>
/// ThemePath parameter
/// </summary>
[Parameter(Position = 2,
Mandatory = false,
HelpMessage = "Theme path")]
[ValidateNotNullOrEmpty]
public string ThemePath
{
set
{
themePath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path;
}
}
/// <summary>
/// ThemePackage parameter
/// </summary>
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
HelpMessage = "Theme path")]
[ValidateNotNullOrEmpty]
public OpenXmlPowerToolsDocument ThemePackage
{
get
{
return themePackage;
}
set
{
themePackage = value;
}
}
#endregion
#region Cmdlet Overrides
/// <summary>
/// Entry point for PowerShell cmdlets
/// </summary>
protected override void ProcessRecord()
{
if (themePath != null)
themePackage = OpenXmlPowerToolsDocument.FromFileName(themePath);
if (themePackage == null)
{
WriteError(new ErrorRecord(new ArgumentException("No theme was specified."), "OpenXmlPowerTools", ErrorCategory.InvalidArgument, null));
}
else
{
foreach (var document in AllDocuments("Set-OpenXmlTheme"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(ThemeAccessor.SetTheme((WmlDocument)document, themePackage));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,89 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Management.Automation;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Set-OpenXmlWatermark cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Set, "OpenXmlWatermark", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class SetOpenXmlWatermarkCmdlet : PowerToolsModifierCmdlet
{
#region Parameters
private bool diagonalOrientation;
private string watermarkText;
/// <summary>
/// WatermarkText parameter
/// </summary>
[Parameter(Position = 2,
Mandatory = true,
ValueFromPipeline = true,
HelpMessage = "Text to show in the watermark")]
[ValidateNotNullOrEmpty]
public string WatermarkText
{
get
{
return watermarkText;
}
set
{
watermarkText = value;
}
}
/// <summary>
/// DiagonalOrientation parameter
/// </summary>
[Parameter(
Mandatory = false,
HelpMessage = "Specifies diagonal orientation for watermark")]
[ValidateNotNullOrEmpty]
public SwitchParameter DiagonalOrientation
{
get
{
return diagonalOrientation;
}
set
{
diagonalOrientation = value;
}
}
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
foreach (var document in AllDocuments("Set-OpenXmlWatermark"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
OutputDocument(WatermarkAccessor.InsertWatermark((WmlDocument)document, watermarkText, diagonalOrientation));
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,64 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2011.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Linq;
using System.Collections.Generic;
using System.Management.Automation;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXmlPowerTools.Commands
{
/// <summary>
/// Split-OpenXmlDocument cmdlet
/// </summary>
[Cmdlet(VerbsCommon.Split, "OpenXmlDocument", SupportsShouldProcess = true)]
[OutputType("OpenXmlPowerToolsDocument")]
public class SplitOpenXmlDocumentCmdlet : PowerToolsModifierCmdlet
{
private int NextNumber;
#region Parameters
[Parameter(Position = 2,
Mandatory = true,
HelpMessage = "Defines the prefix name of resulting documents")
]
public string Prefix;
#endregion
#region Cmdlet Overrides
protected override void ProcessRecord()
{
NextNumber = 1;
foreach (var document in AllDocuments("Split-OpenXmlDocument"))
{
try
{
if (!(document is WmlDocument))
throw new PowerToolsDocumentException("Not a wordprocessing document.");
foreach (WmlDocument item in DocumentBuilder.SplitOnSections((WmlDocument)document))
{
item.FileName = String.Format("{0}{1}.docx", Prefix, NextNumber++);
OutputDocument(item);
}
}
catch (Exception e)
{
WriteError(PowerToolsExceptionHandling.GetExceptionErrorRecord(e, document));
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,26 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
//
// To add a suppression to this file, right-click the message in the
// Error List, point to "Suppress Message(s)", and click
// "In Project Suppression File".
// You do not need to add suppressions to this file manually.
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Scope = "member", Target = "OpenXml.PowerTools.Wordprocessing.WatermarkAccesor.#GetWatermarkText()")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString", Scope = "member", Target = "OpenXml.PowerTools.WorksheetAccessor.#CreateEmptyRow(System.Int32)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString", Scope = "member", Target = "OpenXml.PowerTools.WorksheetAccessor.#AddValue(System.Xml.Linq.XDocument,System.Int32,System.Int32,System.String)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)", Scope = "member", Target = "OpenXml.PowerTools.WorksheetAccessor.#Add(System.Xml.Linq.XDocument)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.IO.StringWriter.#ctor", Scope = "member", Target = "OpenXml.PowerTools.WordprocessingDocumentManager.#TransformToHtml(System.Boolean,System.String,System.String,System.String,System.String)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object,System.Object)", Scope = "member", Target = "OpenXml.PowerTools.WordprocessingDocumentManager.#SplitDocument(OpenXml.PowerTools.WordprocessingDocument,System.String,System.String)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.String.ToUpper", Scope = "member", Target = "OpenXml.PowerTools.SpreadsheetDocumentManager.#GetValueReferences(System.String,System.String,System.Collections.Generic.List`1<System.String>,System.Collections.Generic.List`1<System.String>,System.String[][])")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object[])", Scope = "member", Target = "OpenXml.PowerTools.SpreadsheetDocumentManager.#GetRangeReference(System.String,System.Int32,System.Int32,System.Int32,System.Int32)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object,System.Object)", Scope = "member", Target = "OpenXml.PowerTools.SpreadsheetDocumentManager.#GetRangeReference(System.String,System.Int32,System.Int32)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.String.ToUpper", Scope = "member", Target = "OpenXml.PowerTools.SpreadsheetDocumentManager.#GetHeaderReferences(System.String,System.String,System.Collections.Generic.List`1<System.String>,System.Collections.Generic.List`1<System.String>,System.String[][])")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1307:SpecifyStringComparison", MessageId = "System.String.LastIndexOf(System.String)", Scope = "member", Target = "OpenXml.PowerTools.OpenXmlCmdlet.#CreateBackupFile(System.String)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)", Scope = "member", Target = "OpenXml.PowerTools.OpenXmlCmdlet.#CreateBackupFile(System.String)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.String.ToUpper", Scope = "member", Target = "OpenXml.PowerTools.ExportOpenXmlSpreadsheetCmdlet.#CreateSpreadsheet(System.Collections.ObjectModel.Collection`1<System.Management.Automation.PSObject>)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString", Scope = "member", Target = "OpenXml.PowerTools.ChartsheetAccessor.#CreateEmptyRow(System.Int32)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1307:SpecifyStringComparison", MessageId = "System.String.StartsWith(System.String)", Scope = "member", Target = "OpenXml.PowerTools.ChartsheetAccessor.#Create(OpenXml.PowerTools.ChartType,System.Collections.Generic.List`1<System.String>,System.Collections.Generic.List`1<System.String>,System.String)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)", Scope = "member", Target = "OpenXml.PowerTools.ChartsheetAccessor.#Create(OpenXml.PowerTools.ChartType,System.Collections.Generic.List`1<System.String>,System.Collections.Generic.List`1<System.String>,System.String)")]

View File

@@ -0,0 +1,224 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{4470E36F-6B56-4740-8DA3-685A13EFDE58}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>OpenXmlPowerTools</RootNamespace>
<AssemblyName>OpenXmlPowerTools</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>3.5</OldToolsVersion>
<UpgradeBackupLocation />
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>
</DocumentationFile>
<RunCodeAnalysis>false</RunCodeAnalysis>
<CodeAnalysisRules>-Microsoft.Design#CA1012;-Microsoft.Design#CA2210;-Microsoft.Design#CA1040;-Microsoft.Design#CA1005;-Microsoft.Design#CA1020;-Microsoft.Design#CA1021;-Microsoft.Design#CA1010;-Microsoft.Design#CA1011;-Microsoft.Design#CA1009;-Microsoft.Design#CA1050;-Microsoft.Design#CA1026;-Microsoft.Design#CA1019;-Microsoft.Design#CA1031;-Microsoft.Design#CA1047;-Microsoft.Design#CA1000;-Microsoft.Design#CA1048;-Microsoft.Design#CA1051;-Microsoft.Design#CA1002;-Microsoft.Design#CA1061;-Microsoft.Design#CA1006;-Microsoft.Design#CA1046;-Microsoft.Design#CA1045;-Microsoft.Design#CA1065;-Microsoft.Design#CA1038;-Microsoft.Design#CA1008;-Microsoft.Design#CA1028;-Microsoft.Design#CA1064;-Microsoft.Design#CA1004;-Microsoft.Design#CA1035;-Microsoft.Design#CA1063;-Microsoft.Design#CA1032;-Microsoft.Design#CA1023;-Microsoft.Design#CA1033;-Microsoft.Design#CA1039;-Microsoft.Design#CA1016;-Microsoft.Design#CA1014;-Microsoft.Design#CA1017;-Microsoft.Design#CA1018;-Microsoft.Design#CA1027;-Microsoft.Design#CA1059;-Microsoft.Design#CA1060;-Microsoft.Design#CA1034;-Microsoft.Design#CA1013;-Microsoft.Design#CA1036;-Microsoft.Design#CA1044;-Microsoft.Design#CA1041;-Microsoft.Design#CA1025;-Microsoft.Design#CA1052;-Microsoft.Design#CA1053;-Microsoft.Design#CA1057;-Microsoft.Design#CA1058;-Microsoft.Design#CA1001;-Microsoft.Design#CA1049;-Microsoft.Design#CA1054;-Microsoft.Design#CA1056;-Microsoft.Design#CA1055;-Microsoft.Design#CA1030;-Microsoft.Design#CA1003;-Microsoft.Design#CA1007;-Microsoft.Design#CA1043;-Microsoft.Design#CA1024;-Microsoft.Maintainability#CA1506;-Microsoft.Maintainability#CA1502;-Microsoft.Maintainability#CA1501;-Microsoft.Maintainability#CA1505;-Microsoft.Maintainability#CA1504;-Microsoft.Maintainability#CA1500;-Microsoft.Mobility#CA1600;-Microsoft.Mobility#CA1601;-Microsoft.Naming#CA1702;-Microsoft.Naming#CA1700;-Microsoft.Naming#CA1712;-Microsoft.Naming#CA1713;-Microsoft.Naming#CA1714;-Microsoft.Naming#CA1709;-Microsoft.Naming#CA1704;-Microsoft.Naming#CA1708;-Microsoft.Naming#CA1715;-Microsoft.Naming#CA1710;-Microsoft.Naming#CA1720;-Microsoft.Naming#CA1707;-Microsoft.Naming#CA1722;-Microsoft.Naming#CA1711;-Microsoft.Naming#CA1716;-Microsoft.Naming#CA1717;-Microsoft.Naming#CA1725;-Microsoft.Naming#CA1719;-Microsoft.Naming#CA1721;-Microsoft.Naming#CA1701;-Microsoft.Naming#CA1703;-Microsoft.Naming#CA1724;-Microsoft.Naming#CA1726;-Microsoft.Performance#CA1809;-Microsoft.Performance#CA1811;-Microsoft.Performance#CA1812;-Microsoft.Performance#CA1813;-Microsoft.Performance#CA1823;-Microsoft.Performance#CA1800;-Microsoft.Performance#CA1805;-Microsoft.Performance#CA1810;-Microsoft.Performance#CA1824;-Microsoft.Performance#CA1822;-Microsoft.Performance#CA1815;-Microsoft.Performance#CA1814;-Microsoft.Performance#CA1819;-Microsoft.Performance#CA1821;-Microsoft.Performance#CA1804;-Microsoft.Performance#CA1820;-Microsoft.Performance#CA1802;-Microsoft.Portability#CA1901;-Microsoft.Portability#CA1900;-Microsoft.Reliability#CA2001;-Microsoft.Reliability#CA2002;-Microsoft.Reliability#CA2003;-Microsoft.Reliability#CA2004;-Microsoft.Reliability#CA2006;-Microsoft.Security#CA2116;-Microsoft.Security#CA2117;-Microsoft.Security#CA2105;-Microsoft.Security#CA2115;-Microsoft.Security#CA2102;-Microsoft.Security#CA2104;-Microsoft.Security#CA2122;-Microsoft.Security#CA2114;-Microsoft.Security#CA2123;-Microsoft.Security#CA2111;-Microsoft.Security#CA2108;-Microsoft.Security#CA2107;-Microsoft.Security#CA2103;-Microsoft.Security#CA2118;-Microsoft.Security#CA2109;-Microsoft.Security#CA2119;-Microsoft.Security#CA2106;-Microsoft.Security#CA2112;-Microsoft.Security#CA2120;-Microsoft.Security#CA2121;-Microsoft.Security#CA2126;-Microsoft.Security#CA2124;-Microsoft.Security#CA2127;-Microsoft.Security#CA2128;-Microsoft.Security#CA2129;-Microsoft.Usage#CA2243;-Microsoft.Usage#CA2236;-Microsoft.Usage#CA1816;-Microsoft.Usage#CA2227;-Microsoft.Usage#CA2213;-Microsoft.Usage#CA2216;-Microsoft.Usage#CA2214;-Microsoft.Usage#CA2222;-Microsoft.Usage#CA1806;-Microsoft.Usage#CA2217;-Microsoft.Usage#CA2212;-Microsoft.Usage#CA2219;-Microsoft.Usage#CA2201;-Microsoft.Usage#CA2228;-Microsoft.Usage#CA2221;-Microsoft.Usage#CA2220;-Microsoft.Usage#CA2240;-Microsoft.Usage#CA2229;-Microsoft.Usage#CA2238;-Microsoft.Usage#CA2207;-Microsoft.Usage#CA2208;-Microsoft.Usage#CA2235;-Microsoft.Usage#CA2237;-Microsoft.Usage#CA2232;-Microsoft.Usage#CA2223;-Microsoft.Usage#CA2211;-Microsoft.Usage#CA2233;-Microsoft.Usage#CA2225;-Microsoft.Usage#CA2226;-Microsoft.Usage#CA2231;-Microsoft.Usage#CA2224;-Microsoft.Usage#CA2218;-Microsoft.Usage#CA2234;-Microsoft.Usage#CA2239;-Microsoft.Usage#CA2200;-Microsoft.Usage#CA1801;-Microsoft.Usage#CA2242;-Microsoft.Usage#CA2205;-Microsoft.Usage#CA2230</CodeAnalysisRules>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="DocumentFormat.OpenXml, Version=2.5.5631.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Omega\bin\Release\DocumentFormat.OpenXml.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration.Install" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Management.Automation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\System.Management.Automation.dll</HintPath>
</Reference>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Classes\BackgroundAccessor.cs" />
<Compile Include="Classes\ChartsheetAccessor.cs" />
<Compile Include="Classes\CommentAccessor.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Classes\CommentMerger.cs" />
<Compile Include="Classes\DocumentComparer.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Classes\StyleAccessor.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Cmdlets\ConfirmOpenXmlValidCmdlet.cs" />
<Compile Include="Classes\ContentFormatAccessor.cs" />
<Compile Include="Classes\ContentStyleAccessor.cs" />
<Compile Include="Classes\DocumentBuilder.cs" />
<Compile Include="Classes\HtmlConverter.cs" />
<Compile Include="Classes\IndexAccessor.cs" />
<Compile Include="Classes\ListItemRetriever.cs" />
<Compile Include="Classes\MarkupSimplifier.cs" />
<Compile Include="Classes\PtOpenXmlUtil.cs" />
<Compile Include="Classes\PtUtil.cs" />
<Compile Include="Classes\RevisionAccepter.cs" />
<Compile Include="Classes\SpreadSheetStyleAccessor.cs" />
<Compile Include="Classes\SpreadSheetTableAccessor.cs" />
<Compile Include="Classes\TextReplacer.cs" />
<Compile Include="Classes\ReferenceAdder.cs" />
<Compile Include="Classes\CustomXmlAccessor.cs" />
<Compile Include="Classes\DigitalSignatureAccessor.cs" />
<Compile Include="Classes\FooterAccessor.cs" />
<Compile Include="Classes\HeaderAccessor.cs" />
<Compile Include="Classes\PtOpenXmlDocument.cs" />
<Compile Include="Classes\PictureAccessor.cs" />
<Compile Include="Classes\SettingAccessor.cs" />
<Compile Include="Classes\ThemeAccessor.cs" />
<Compile Include="Classes\WatermarkAccessor.cs" />
<Compile Include="Classes\WordprocessingDocumentManager.cs" />
<Compile Include="Classes\SpreadsheetDocumentManager.cs" />
<Compile Include="Classes\PowerToolsExtensions.cs" />
<Compile Include="Classes\WorksheetAccessor.cs" />
<Compile Include="Cmdlets\EditOpenXmlChangeCmdlet.cs" />
<Compile Include="Cmdlets\AddOpenXmlDigitalSignatureCmdlet.cs" />
<Compile Include="Cmdlets\AddOpenXmlSpreadSheetTableCmdlet.cs" />
<Compile Include="Cmdlets\MergeOpenXmlDocumentCmdlet.cs" />
<Compile Include="Cmdlets\MergeOpenXmlDocumentCommentCmdlet.cs" />
<Compile Include="Cmdlets\RemoveOpenXmlDigitalSignatureCmdlet.cs" />
<Compile Include="Cmdlets\AddOpenXmlDocumentIndexCmdlet.cs" />
<Compile Include="Cmdlets\GetOpenXmlCommentCmdlet.cs" />
<Compile Include="Cmdlets\AddOpenXmlDocumentTOACmdlet.cs" />
<Compile Include="Cmdlets\AddOpenXmlDocumentTOFCmdlet.cs" />
<Compile Include="Cmdlets\RemoveOpenXmlPersonalInformationCmdlet.cs" />
<Compile Include="Cmdlets\SelectOpenXmlStringCmdlet.cs" />
<Compile Include="Cmdlets\SetOpenXmlSpreadSheetCellStyleCmdlet.cs" />
<Compile Include="Cmdlets\SetOpenXmlSpreadSheetCellValueCmdlet.cs" />
<Compile Include="Cmdlets\SetOpenXmlSpreadSheetColumnWidthCmdlet.cs" />
<Compile Include="Cmdlets\SetOpenXmlStringCmdlet.cs" />
<Compile Include="Cmdlets\SetOpenXmlThemeCmdlet.cs" />
<Compile Include="Cmdlets\AddOpenXmlDocumentTOCCmdlet.cs" />
<Compile Include="Cmdlets\GetOpenXmlThemeCmdlet.cs" />
<Compile Include="Cmdlets\ExportOpenXmlWordprocessingCmdlet.cs" />
<Compile Include="Cmdlets\GetOpenXmlBackgroundCmdlet.cs" />
<Compile Include="Cmdlets\GetOpenXmlCustomXmlDataCmdlet.cs" />
<Compile Include="Cmdlets\GetOpenXmlDigitalSignatureCmdlet.cs" />
<Compile Include="Cmdlets\GetOpenXmlDocumentCmdlet.cs" />
<Compile Include="Cmdlets\GetOpenXmlFooterCmdlet.cs" />
<Compile Include="Cmdlets\GetOpenXmlHeaderCmdlet.cs" />
<Compile Include="Cmdlets\GetOpenXmlStyleCmdlet.cs" />
<Compile Include="Cmdlets\AddOpenXmlPictureCmdlet.cs" />
<Compile Include="Cmdlets\AddOpenXmlContentCmdlet.cs" />
<Compile Include="Cmdlets\GetOpenXmlWatermarkCmdlet.cs" />
<Compile Include="Cmdlets\LockOpenXmlDocumentCmdlet.cs" />
<Compile Include="Cmdlets\ExportOpenXmlSpreadsheetCmdlet.cs" />
<Compile Include="Cmdlets\OpenXmlCmdlet.cs" />
<Compile Include="Cmdlets\RemoveOpenXmlCommentCmdlet.cs" />
<Compile Include="Cmdlets\SetOpenXmlBackgroundCmdlet.cs" />
<Compile Include="Cmdlets\SetOpenXmlContentFormatCmdlet.cs" />
<Compile Include="Cmdlets\SetOpenXmlContentStyleCmdlet.cs" />
<Compile Include="Cmdlets\SetOpenXmlCustomXmlDataCmdlet.cs" />
<Compile Include="Cmdlets\SetOpenXmlFooterCmdlet.cs" />
<Compile Include="Cmdlets\SetOpenXmlHeaderCmdlet.cs" />
<Compile Include="Cmdlets\SetOpenXmlStyleCmdlet.cs" />
<Compile Include="Cmdlets\ExportOpenXmlToHtmlCmdlet.cs" />
<Compile Include="Cmdlets\SetOpenXmlWatermarkCmdlet.cs" />
<Compile Include="Cmdlets\RemoveOpenXmlMarkupCmdlet.cs" />
<Compile Include="Cmdlets\SplitOpenXmlDocumentCmdlet.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="OpenXmlPowerToolsSnapin.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="OpenXmlPowerTools.dll-Help.xml" />
</ItemGroup>
<ItemGroup>
<WCFMetadata Include="Service References\" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
<Visible>False</Visible>
<ProductName>Windows Installer 3.1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<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>
-->
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
<PreBuildEvent>copy ..\..\OpenXmlPowerTools.dll-Help.xml .</PreBuildEvent>
</PropertyGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,80 @@
/***************************************************************************
Copyright (c) Microsoft Corporation 2008.
This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here:
http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx
***************************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Management.Automation;
using System.ComponentModel;
namespace OpenXmlPowerTools
{
/// <summary>
/// SnapIn containing OpenXml Power Tools Cmdlets
/// </summary>
[RunInstaller(true)]
public class OpenXmlPowerToolsSnapIn : PSSnapIn
{
/// <summary>
/// SnapIn name
/// </summary>
public override string Name
{
get
{
return "OpenXmlPowerTools";
}
}
/// <summary>
/// SnapIn vendor
/// </summary>
public override string Vendor
{
get
{
return "Staff DotNet";
}
}
/// <summary>
/// SnapIn vendor resource
/// </summary>
public override string VendorResource
{
get
{
return "OpenXml Power Tools, Staff DotNet";
}
}
/// <summary>
/// SnapIn description
/// </summary>
public override string Description
{
get
{
return "A set of cmdlets to manipulate OpenXml documents";
}
}
/// <summary>
/// SnapIn description resource
/// </summary>
public override string DescriptionResource
{
get
{
return "OpenXml Power Tools, A set of cmdlets to manipulate OpenXml documents";
}
}
}
}

View File

@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("OpenXml PowerTools")]
[assembly: AssemblyDescription("OpenXml Power Tools - Cmdlets to manipulate OpenXml documents")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("OpenXml Power Tools")]
[assembly: AssemblyCopyright("Copyright © Microsoft Corporation 2011")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("916550ef-5188-43a5-b95c-4c975e54ede6")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.2.0.0")]
[assembly: AssemblyFileVersion("0.1.0.0")]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5.2", FrameworkDisplayName = ".NET Framework 4.5.2")]

View File

@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]

View File

@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]

View File

@@ -0,0 +1 @@
932fd781a80456d6e3a540da687d2cf47b00072e

View File

@@ -0,0 +1 @@
139ddb9882cf10514aa184935489ddb5eafe895a

View File

@@ -0,0 +1,26 @@
C:\Projects\OmegaPro\PowerTools\obj\Release\OpenXml Power Tools.csproj.CoreCompileInputs.cache
I:\projects\OmegaPro\PowerTools\bin\Release\OpenXmlPowerTools.dll
I:\projects\OmegaPro\PowerTools\bin\Release\OpenXmlPowerTools.pdb
I:\projects\OmegaPro\PowerTools\bin\Release\DocumentFormat.OpenXml.dll
I:\projects\OmegaPro\PowerTools\obj\Release\OpenXml Power Tools.csproj.CoreCompileInputs.cache
I:\projects\OmegaPro\PowerTools\obj\Release\OpenXml Power Tools.csproj.CopyComplete
I:\projects\OmegaPro\PowerTools\obj\Release\OpenXmlPowerTools.dll
I:\projects\OmegaPro\PowerTools\obj\Release\OpenXmlPowerTools.pdb
I:\projects\OmegaPro\PowerTools\obj\Release\OpenXml Power Tools.csprojAssemblyReference.cache
H:\projects\OmegaPro\PowerTools\bin\Release\OpenXmlPowerTools.dll
H:\projects\OmegaPro\PowerTools\bin\Release\OpenXmlPowerTools.pdb
H:\projects\OmegaPro\PowerTools\bin\Release\DocumentFormat.OpenXml.dll
H:\projects\OmegaPro\PowerTools\obj\Release\OpenXml Power Tools.csproj.AssemblyReference.cache
H:\projects\OmegaPro\PowerTools\obj\Release\OpenXml Power Tools.csproj.CoreCompileInputs.cache
H:\projects\OmegaPro\PowerTools\obj\Release\OpenXml Power Tools.csproj.CopyComplete
H:\projects\OmegaPro\PowerTools\obj\Release\OpenXmlPowerTools.dll
H:\projects\OmegaPro\PowerTools\obj\Release\OpenXmlPowerTools.pdb
J:\projects\OmegaPro\PowerTools\bin\Release\OpenXmlPowerTools.dll
J:\projects\OmegaPro\PowerTools\bin\Release\OpenXmlPowerTools.pdb
J:\projects\OmegaPro\PowerTools\bin\Release\DocumentFormat.OpenXml.dll
J:\projects\OmegaPro\PowerTools\bin\Release\DocumentFormat.OpenXml.xml
J:\projects\OmegaPro\PowerTools\obj\Release\OpenXml Power Tools.csproj.AssemblyReference.cache
J:\projects\OmegaPro\PowerTools\obj\Release\OpenXml Power Tools.csproj.CoreCompileInputs.cache
J:\projects\OmegaPro\PowerTools\obj\Release\OpenXml Power Tools.csproj.CopyComplete
J:\projects\OmegaPro\PowerTools\obj\Release\OpenXmlPowerTools.dll
J:\projects\OmegaPro\PowerTools\obj\Release\OpenXmlPowerTools.pdb

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More