Alexey,
I appreciate your actually trying to address the issue I posted (Awais Hafeez’s response was not relevant.
In fact, the information you provided looks promising if you could help me debug an error in the work-around code you referenced.
I have provided sample code (slightly modified from the previous sample). If there is no text before the first tag, I get the following error:
“Cannot return user defined styles by style identifier.”
on line:
prop.SetValue(dest, prop.GetValue(source, null), null);
in
CopyFormatting()
In the following sample code that I provided, delete the following text “error occurs if no text prior to div”
and the error will occur. Note, I have included the work-around code in this post as well.
my code: ____________________________________
public void AsposeTest()
{
Aspose.Words.License license = new Aspose.Words.License();
license.SetLicense("Aspose.Total.lic");
string someText = "error occurs if no text prior to div<div class = 'test'>text in a div</div>Lorem ipsum";
string css = "<style type = 'text/css'>" + ".test{color:Red;}" + "</style>";
Document doc = null;
DocumentBuilder builder = null;
doc = new Document();
builder = new DocumentBuilder(doc);
InsertHtmlWithBuilderFormatting(builder, css + someText);
doc.Save(Response, "filename.doc", ContentDisposition.Attachment, SaveOptions.CreateSaveOptions(SaveFormat.Doc));
Response.End();
}
work-around code:________________________________________
/// <summary>
///
/// Inserts an HTML snippet into document using the current formatting from the supplied DocumentBuilder object.
/// Copies over public members of the Font, ParagraphFormat, ListFormat, RowFormat and CellFormat from the DocumentBuilder
/// object onto the appropriate nodes. The formatting on the HTML takes precedence.
/// </summary>
/// <param name="builder">The DocumentBuilder object which formatting is copied from</param>
/// <param name="html">The HTML string to insert</param>
public static void InsertHtmlWithBuilderFormatting(DocumentBuilder builder, string html)
{
ArrayList nodes = new ArrayList();
Document doc = builder.Document;
// Store any callback already set on this document
INodeChangingCallback origCallback = doc.NodeChangingCallback;
// Stores nodes inserted during the InsertHtml call.
doc.NodeChangingCallback = new HandleNodeChanging(nodes);
// Some properties may be changed during InsertHTML, try using a brand new builder instead.
DocumentBuilder htmlBuilder = new DocumentBuilder(doc);
// Move to current paragraph of the original builder
if (builder.CurrentParagraph != null)
htmlBuilder.MoveTo(builder.CurrentParagraph);
// Check if a specific inline node is selected move to this instead
if (builder.CurrentNode != null)
htmlBuilder.MoveTo(builder.CurrentNode);
// Insert HTML.
htmlBuilder.InsertHtml(html);
// Restore the original callback
doc.NodeChangingCallback = origCallback;
// Go through every inserted node and copy formatting from the DocumentBuilder to the apporpriate nodes.
foreach (Node node in nodes)
{
if (node.NodeType == NodeType.Run)
{
Run run = (Run)node;
// Copy formatting of the builder's font to the font of the run.
CopyFormatting(builder.Font, run.Font, htmlBuilder.Font);
}
else if (node.NodeType == NodeType.Paragraph)
{
Paragraph para = (Paragraph)node;
// Copy formatting of the builder's paragraph and list formatting to the formatting of the paragraph.
CopyFormatting(builder.ParagraphFormat, para.ParagraphFormat, htmlBuilder.ParagraphFormat);
CopyFormatting(builder.ListFormat, para.ListFormat, htmlBuilder.ListFormat);
}
else if (node.NodeType == NodeType.Cell)
{
Cell cell = (Cell)node;
// Copy formatting of the builder's cell formatting to the cell.
CopyFormatting(builder.CellFormat, cell.CellFormat, htmlBuilder.CellFormat);
}
else if (node.NodeType == NodeType.Row)
{
Row row = (Row)node;
// Copy formatting of the builder's row formatting to the row
CopyFormatting(builder.RowFormat, row.RowFormat, htmlBuilder.RowFormat);
}
}
// Move the original builder to where the temporary builder ended up
if (htmlBuilder.CurrentParagraph != null)
builder.MoveTo(htmlBuilder.CurrentParagraph);
// Move to specific inline node if possible.
if (htmlBuilder.CurrentNode != null)
builder.MoveTo(htmlBuilder.CurrentNode);
}
public class HandleNodeChanging : INodeChangingCallback
{
ArrayList mNodes;
public HandleNodeChanging(ArrayList nodes)
{
mNodes = nodes;
}
void INodeChangingCallback.NodeInserted(NodeChangingArgs args)
{
mNodes.Add(args.Node);
}
void INodeChangingCallback.NodeInserting(NodeChangingArgs args)
{
// Do Nothing
}
void INodeChangingCallback.NodeRemoved(NodeChangingArgs args)
{
// Do Nothing
}
void INodeChangingCallback.NodeRemoving(NodeChangingArgs args)
{
// Do Nothing
}
}
/// <summary>
/// Uses reflection to copy properties from one object to another of the same type.
/// Not recommended for use on non-formatting related classes.
/// </summary>
/// <param name="source">The source formatting object</param>
/// <param name="dest">The destination formatting object</param>
public static void CopyFormatting(Object source, Object dest, Object compare)
{
if (source.GetType() != dest.GetType() && source.GetType() != compare.GetType())
throw new ArgumentException("All objects must be of the same type");
// Iterate through each property in the source object.
foreach (PropertyInfo prop in source.GetType().GetProperties())
{
// Skip indexed access items. Skip setting the internals of a style as these should not be changed.
if (prop.Name == "Item" || prop.Name == "Style")
continue;
object value;
// Wrap this call as it can throw an exception. Skip if thrown
try
{
value = prop.GetValue(source, null);
}
catch (Exception)
{
continue;
}
// Skip if value can not be retrieved.
if (value != null)
{
// If this property returns a class which belongs to the
if (value.GetType().IsClass && prop.GetGetMethod().ReturnType.Assembly.ManifestModule.Name == "Aspose.Words.dll")
{
// Recurse into this class.
CopyFormatting(prop.GetValue(source, null), prop.GetValue(dest, null), prop.GetValue(compare, null));
}
else if (prop.CanWrite)
{
// dest value != default dont copy
if (prop.GetValue(dest, null).Equals(prop.GetValue(compare, null)))
{
// If we can write to this property then copy the value across.
prop.SetValue(dest, prop.GetValue(source, null), null);
}
}
}
}
}