/* * Notes on line spacing * * the w:line and w:lineRule attributes control spacing between lines - including between lines within a paragraph * * If w:spacing w:lineRule="auto" then * w:spacing w:line is a percentage where 240 == 100% * * (line value / 240) * 100 = percentage of line * * If w:spacing w:lineRule="exact" or w:lineRule="atLeast" then * w:spacing w:line is in twips * 1440 = exactly one inch from line to line * * Handle * - ind * - jc * - numPr * - pBdr * - shd * - spacing * - textAlignment * * Don't Handle (yet) * - adjustRightInd? * - autoSpaceDE * - autoSpaceDN * - bidi * - contextualSpacing * - divId * - framePr * - keepLines * - keepNext * - kinsoku * - mirrorIndents * - overflowPunct * - pageBreakBefore * - snapToGrid * - suppressAutoHyphens * - suppressLineNumbers * - suppressOverlap * - tabs * - textBoxTightWrap * - textDirection * - topLinePunct * - widowControl * - wordWrap * */ private static object ConvertParagraph(WordprocessingDocument wordDoc, HtmlConverterSettings settings, XElement paragraph, XName elementName, bool suppressTrailingWhiteSpace, decimal currentMarginLeft, bool isBidi) { var style = new Dictionary<string, string>(); var sn = (string)paragraph.Attribute(PtOpenXml.StyleName); if (sn != null) style.Add("PtStyleName", sn); XElement pPr = paragraph.Element(W.pPr); if (pPr != null) { var spacing = pPr.Element(W.spacing); if (spacing != null) { var spacingBefore = (decimal?)spacing.Attribute(W.before); if (spacingBefore != null) style.AddIfMissing("margin-top", string.Format("{0}pt", spacingBefore / 20.0m)); var lineRule = (string)spacing.Attribute(W.lineRule); if (lineRule == "auto") { var line = (decimal)spacing.Attribute(W.line); if (line != 240m) { var pct = (line / 240m) * 100m; style.Add("line-height", string.Format("{0:0.0}%", pct)); } } if (lineRule == "exact") { var line = (decimal)spacing.Attribute(W.line); var points = line / 20m; style.Add("line-height", string.Format("{0:0.0}pt", points)); } if (lineRule == "atLeast") { var line = (decimal)spacing.Attribute(W.line); var points = line / 20m; if (points >= 14m) style.Add("line-height", string.Format("{0:0.0}pt", points)); } decimal? spacingAfter; if (suppressTrailingWhiteSpace) spacingAfter = 0; else spacingAfter = (decimal?)spacing.Attribute(W.after) /*+ addToSpacing*/; if (spacingAfter != null) style.AddIfMissing("margin-bottom", string.Format("{0}pt", spacingAfter / 20.0m)); } var ind = pPr.Element(W.ind); if (ind != null) { decimal? left = (decimal?)ind.Attribute(W.left); if (left != null) { decimal leftInInches = (decimal)left / 1440 - currentMarginLeft; style.AddIfMissing(isBidi ? "margin-right" : "margin-left", string.Format("{0:0.00}in", leftInInches)); } decimal? right = (decimal?)ind.Attribute(W.right); if (right != null) { decimal rightInInches = (decimal)right / 1440; style.AddIfMissing(isBidi ? "margin-left" : "margin-right", string.Format("{0:0.00}in", rightInInches)); } decimal? firstLine = (decimal?)ind.Attribute(W.firstLine); if (firstLine != null) { decimal firstLineInInches = (decimal)firstLine / 1440m; style.AddIfMissing("text-indent", string.Format("{0:0.00}in", firstLineInInches)); } decimal? hanging = (decimal?)ind.Attribute(W.hanging); if (hanging != null) { decimal hangingInInches = (decimal)-hanging / 1440m; style.AddIfMissing("text-indent", string.Format("{0:0.00}in", hangingInInches)); } } // todo need to handle // - both // - mediumKashida // - distribute // - numTab // - highKashida // - lowKashida // - thaiDistribute var jcVal = (string)pPr.Elements(W.jc).Attributes(W.val).FirstOrDefault(); if (jcVal == null) { jcVal = "left"; } if (jcVal == "left") { if (isBidi) style.AddIfMissing("text-align", "right"); else style.AddIfMissing("text-align", "left"); } else if (jcVal == "right") { if (isBidi) style.AddIfMissing("text-align", "left"); else style.AddIfMissing("text-align", "right"); } else if (jcVal == "center") style.AddIfMissing("text-align", "center"); else if (jcVal == "both") style.AddIfMissing("text-align", "justify"); CreateStyleFromShd(style, pPr.Element(W.shd)); // Pt.FontName string font = (string)paragraph.Attributes(PtOpenXml.FontName).FirstOrDefault(); if (font != null) CreateFontCssProperty(font, style); // W.sz decimal? sz = null; var languageType = (string)paragraph.Attribute(PtOpenXml.LanguageType); if (languageType == "bidi") sz = (decimal?)pPr.Elements(W.rPr).Elements(W.szCs).Attributes(W.val).FirstOrDefault(); else sz = (decimal?)pPr.Elements(W.rPr).Elements(W.sz).Attributes(W.val).FirstOrDefault(); var sizesOfAllRunsInParagraph = paragraph .DescendantsTrimmed(W.txbxContent) .Select(run => { if (run.Name != W.r) return null; var runLanguageType = (string)run.Attribute(PtOpenXml.LanguageType); if (runLanguageType == "bidi") { var runCsSz = (decimal?)run .Elements(W.rPr) .Elements(W.szCs) .Attributes(W.val) .FirstOrDefault(); return runCsSz; } else { var runSz = (decimal?)run .Elements(W.rPr) .Elements(W.sz) .Attributes(W.val) .FirstOrDefault(); return runSz; } }) .Where(runSz => runSz != null); if (sizesOfAllRunsInParagraph.Any()) sz = sizesOfAllRunsInParagraph.Cast<decimal>().Max(); if (sz != null) style.AddIfMissing("font-size", string.Format("{0}pt", sz / 2.0m)); var languageTypeOfAllRunsInParagraph = paragraph .DescendantsTrimmed(W.txbxContent) .Select(run => { if (run.Name != W.r) return null; var runLanguageType = (string)run.Attribute(PtOpenXml.LanguageType); return runLanguageType; }) .Where(runSz => runSz != null); if (!languageTypeOfAllRunsInParagraph.Any(lt => lt == "bidi")) style.AddIfMissing("line-height", "108%"); // vertical text alignment as of December 2013 does not work in any major browsers. var verticalTextAlignment = (string)pPr.Elements(W.textAlignment).Attributes(W.val).FirstOrDefault(); if (verticalTextAlignment != null && verticalTextAlignment != "auto") { if (verticalTextAlignment == "top") style.AddIfMissing("vertical-align", "top"); else if (verticalTextAlignment == "center") style.AddIfMissing("vertical-align", "middle"); else if (verticalTextAlignment == "baseline") style.AddIfMissing("vertical-align", "baseline"); else if (verticalTextAlignment == "bottom") style.AddIfMissing("vertical-align", "bottom"); } style.AddIfMissing("margin-top", "0pt"); style.AddIfMissing("margin-left", "0pt"); style.AddIfMissing("margin-right", "0pt"); style.AddIfMissing("margin-bottom", ".001pt"); } XAttribute rtl = null; XEntity firstMark = null; if (isBidi) { rtl = new XAttribute("dir", "rtl"); firstMark = new XEntity("#x200f"); // RLM } else { rtl = new XAttribute("dir", "ltr"); } var paraElement = new XElement(elementName, rtl, firstMark, ConvertContentThatCanContainFields(wordDoc, settings, paragraph.Elements())); paraElement.AddAnnotation(style); return paraElement; }
/* * Handle: * - b * - bdr * - caps * - color * - dstrike * - highlight * - i * - position * - rFonts * - shd * - smallCaps * - spacing * - strike * - sz * - u * - vanish * - vertAlign * * Don't handle: * - em * - emboss * - fitText * - imprint * - kern * - outline * - shadow * - w * */ private static object ConvertRun(WordprocessingDocument wordDoc, HtmlConverterSettings settings, XElement run) { var style = new Dictionary<string, string>(); var sn = (string)run.Attribute(PtOpenXml.StyleName); if (sn != null) style.Add("PtStyleName", sn); var rPr = run.Element(W.rPr); if (rPr == null) { object content2 = run.Elements().Select(e => ConvertToHtmlTransform(wordDoc, settings, e, false, 0m)); return content2; } // hide all content that contains the w:rPr/w:webHidden element if (rPr.Element(W.webHidden) != null) return null; // W.bdr if (rPr.Element(W.bdr) != null && (string)rPr.Elements(W.bdr).Attributes(W.val).FirstOrDefault() != "none") { style.AddIfMissing("border", "solid windowtext 1.0pt"); style.AddIfMissing("padding", "0in"); } // W.color string color = (string)rPr.Elements(W.color).Attributes(W.val).FirstOrDefault(); if (color != null) CreateColorProperty("color", color, style); // W.highlight string highlight = (string)rPr.Elements(W.highlight).Attributes(W.val).FirstOrDefault(); if (highlight != null) CreateColorProperty("background", highlight, style); // W.shd string shade = (string)rPr.Elements(W.shd).Attributes(W.fill).FirstOrDefault(); if (shade != null) CreateColorProperty("background", shade, style); // Pt.FontName string font = null; if (run.Element(W.sym) != null) font = (string)run.Elements(W.sym).Attributes(W.font).FirstOrDefault(); else font = (string)run.Attributes(PtOpenXml.FontName).FirstOrDefault(); if (font != null) CreateFontCssProperty(font, style); // W.sz var languageType = (string)run.Attribute(PtOpenXml.LanguageType); decimal? sz = null; if (languageType == "bidi") sz = (decimal?)rPr.Elements(W.szCs).Attributes(W.val).FirstOrDefault(); else sz = (decimal?)rPr.Elements(W.sz).Attributes(W.val).FirstOrDefault(); if (sz != null) style.AddIfMissing("font-size", string.Format("{0}pt", sz / 2.0m)); // W.caps if (getBoolProp(rPr, W.caps)) style.AddIfMissing("text-transform", "uppercase"); // W.smallCaps if (getBoolProp(rPr, W.smallCaps)) style.AddIfMissing("font-variant", "small-caps"); // W.spacing decimal? spacingInTwips = (decimal?)rPr.Elements(W.spacing).Attributes(W.val).FirstOrDefault(); if (spacingInTwips != null) style.AddIfMissing("letter-spacing", string.Format("{0}pt", spacingInTwips / 20)); // W.position decimal? position = (decimal?)rPr.Elements(W.position).Attributes(W.val).FirstOrDefault(); if (position != null) { style.AddIfMissing("position", "relative"); style.AddIfMissing("top", string.Format("{0}pt", -(position / 2))); } // W.vanish if (getBoolProp(rPr, W.vanish)) style.AddIfMissing("display", "none"); object content = run.Elements().Select(e => ConvertToHtmlTransform(wordDoc, settings, e, false, 0m)); // W.u if (rPr.Element(W.u) != null && (string)rPr.Elements(W.u).Attributes(W.val).FirstOrDefault() != "none") { var newContent = new XElement(Xhtml.u, content); if (newContent.Nodes().Any()) content = newContent; style.AddIfMissing("text-decoration", "underline"); } // W.i if (getBoolProp(rPr, W.i)) { var newContent = new XElement(Xhtml.i, content); if (newContent.Nodes().Any()) content = newContent; style.AddIfMissing("font-style", "italic"); } // W.b if (getBoolProp(rPr, W.b)) { var newContent = new XElement(Xhtml.b, content); if (newContent.Nodes().Any()) content = newContent; style.AddIfMissing("font-weight", "bold"); } else { style.AddIfMissing("font-weight", "normal"); } // W.strike if (getBoolProp(rPr, W.strike) || getBoolProp(rPr, W.dstrike)) { var newContent = new XElement(Xhtml.s, content); if (newContent.Nodes().Any()) content = newContent; style.AddIfMissing("text-decoration", "line-through"); } // W.vertAlign if (rPr.Element(W.vertAlign) != null && (string)rPr.Elements(W.vertAlign).Attributes(W.val).FirstOrDefault() == "superscript") { var newContent = new XElement(Xhtml.sup, content); if (newContent.Nodes().Any()) content = newContent; } if (rPr.Element(W.vertAlign) != null && (string)rPr.Elements(W.vertAlign).Attributes(W.val).FirstOrDefault() == "subscript") { var newContent = new XElement(Xhtml.sub, content); if (newContent.Nodes().Any()) content = newContent; } var rtl = rPr.Element(W.rtl); var isRtl = rtl != null; var paragraph = run.Ancestors(W.p).FirstOrDefault(); var paraBidi = paragraph .Elements(W.pPr) .Elements(W.bidi) .Where(b => b.Attribute(W.val) == null || b.Attribute(W.val).ToBoolean() == true) .FirstOrDefault(); var paraIsBidi = paraBidi != null; string lang = null; if (languageType == "western") lang = (string)rPr.Elements(W.lang).Attributes(W.val).FirstOrDefault(); else if (languageType == "bidi") lang = (string)rPr.Elements(W.lang).Attributes(W.bidi).FirstOrDefault(); else if (languageType == "eastAsia") lang = (string)rPr.Elements(W.lang).Attributes(W.eastAsia).FirstOrDefault(); // only do the following for text runs. XEntity runStartMark = null; XEntity runEndMark = null; // Can't add directional marks if the font-family is symbol - they are visible, and display as a ? bool addDirectionalMarks = true; if (style.ContainsKey("font-family")) { if (style["font-family"].ToLower() == "symbol") addDirectionalMarks = false; } if (addDirectionalMarks) { if (run.Element(W.t) != null) { if (isRtl) { runStartMark = new XEntity("#x200f"); // RLM runEndMark = new XEntity("#x200f"); // RLM } else { if (paraIsBidi) { runStartMark = new XEntity("#x200e"); // LRM runEndMark = new XEntity("#x200e"); // LRM } } } } string defaultLanguage = "en-US"; // todo need to get defaultLanguage if (lang == null) lang = defaultLanguage; XAttribute langAttribute = new XAttribute("lang", lang); if (lang == defaultLanguage) langAttribute = null; if (style.Any() || isRtl || langAttribute != null) { style.AddIfMissing("margin", "0in"); style.AddIfMissing("padding", "0in"); var xe = new XElement(Xhtml.span, langAttribute, runStartMark, content, runEndMark); xe.AddAnnotation(style); content = xe; } return content; }
private static object ConvertToHtmlTransform(WordprocessingDocument wordDoc, HtmlConverterSettings settings, XNode node, bool suppressTrailingWhiteSpace, decimal currentMarginLeft) { 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("http-equiv", "Content-Type"), new XAttribute("content", "text/html; charset=utf-8")), new XElement(Xhtml.meta, new XAttribute("name", "Generator"), new XAttribute("content", "PowerTools for Open XML")), settings.PageTitle != null ? new XElement(Xhtml.title, new XText(settings.PageTitle)) : null ), element.Elements().Select(e => ConvertToHtmlTransform(wordDoc, settings, e, false, currentMarginLeft)) ); // Transform the w:body element to the XHTML h:body element. if (element.Name == W.body) { var sectionDivContent = new XElement(Xhtml.body, CreateSectionDivs(wordDoc, settings, element)); return sectionDivContent; } if (element.Name == W.p) { var bidi = element .Elements(W.pPr) .Elements(W.bidi) .Where(b => b.Attribute(W.val) == null || b.Attribute(W.val).ToBoolean() == true) .FirstOrDefault(); var isBidi = bidi != null; string styleId = (string)element.Elements(W.pPr).Elements(W.pStyle) .Attributes(W.val).FirstOrDefault(); if (styleId != null) { 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 && outlineLevel <= 5) { XName elementName = Xhtml.xhtml + string.Format("h{0}", outlineLevel + 1); return ConvertParagraph(wordDoc, settings, element, elementName, suppressTrailingWhiteSpace, currentMarginLeft, isBidi); } else { XName elementName = Xhtml.p; var o = ConvertParagraph(wordDoc, settings, element, elementName, suppressTrailingWhiteSpace, currentMarginLeft, isBidi); return o; } } } else { XName elementName = Xhtml.p; var o = ConvertParagraph(wordDoc, settings, element, elementName, suppressTrailingWhiteSpace, currentMarginLeft, isBidi); return o; } } // Transform hyperlinks to the XHTML h:A element. if (element.Name == W.hyperlink && element.Attribute(R.id) != null) { try { return new XElement(Xhtml.A, new XAttribute("href", wordDoc.MainDocumentPart .HyperlinkRelationships .Where(x => x.Id == (string)element.Attribute(R.id)) .First() .Uri ), element.Elements(W.r).Select(run => ConvertRun(wordDoc, settings, run)) ); } catch (UriFormatException) { return element.Elements().Select(e => ConvertToHtmlTransform(wordDoc, settings, e, false, currentMarginLeft)); } } // Transform hyperlinks to bookmarks to the XHTML h:A element. if (element.Name == W.hyperlink && element.Attribute(W.anchor) != null) { var style = new Dictionary<string, string>(); var a = new XElement(Xhtml.A, new XAttribute("href", "#" + (string)element.Attribute(W.anchor)), element .Elements(W.r) .Select(run => ConvertRun(wordDoc, settings, run))); style.Add("text-decoration", "none"); a.AddAnnotation(style); return a; } // Transform contents of runs. if (element.Name == W.r) return ConvertRun(wordDoc, settings, element); // Transform w:bookmarkStart into anchor if (element.Name == W.bookmarkStart) { var name = (string)element.Attribute(W.name); if (name != null) { var style = new Dictionary<string, string>(); var a = new XElement(Xhtml.A, new XAttribute("id", name), new XText("")); style.Add("text-decoration", "none"); a.AddAnnotation(style); return a; } } // Transform every w:t element to a text node. if (element.Name == W.t) { var textWithEntities = ConvertEntities(element.Value); return textWithEntities; } // Transform symbols to spans if (element.Name == W.sym) { var cs = (string)element.Attribute(W._char); var c = Convert.ToInt32(cs, 16); var symbolSpan = new XElement(Xhtml.span, new XEntity(string.Format("#{0}", ((int)c).ToString()))); return symbolSpan; } // Transform tabs that have the pt:TabWidth attribute set if (element.Name == W.tab) { var tabWidthAtt = element.Attribute(PtOpenXml.TabWidth); if (tabWidthAtt != null) { var leader = (string)element.Attribute(PtOpenXml.Leader); var tabWidth = (decimal)tabWidthAtt; var style = new Dictionary<string, string>(); XElement span; if (leader != null) { var leaderChar = "."; if (leader == "hyphen") leaderChar = "-"; else if (leader == "dot") leaderChar = "."; else if (leader == "underscore") leaderChar = "_"; var runContainingTabToReplace = element.Ancestors(W.r).First(); var fontNameAtt = runContainingTabToReplace.Attribute(PtOpenXml.pt + "FontName"); if (fontNameAtt == null) fontNameAtt = runContainingTabToReplace.Ancestors(W.p).First() .Attribute(PtOpenXml.pt + "FontName"); var dummyRun = new XElement(W.r, fontNameAtt, runContainingTabToReplace.Elements(W.rPr), new XElement(W.t, leaderChar)); var widthOfLeaderChar = CalcWidthOfRunInTwips(dummyRun); bool forceArial = false; if (widthOfLeaderChar == 0) { dummyRun = new XElement(W.r, new XAttribute(PtOpenXml.FontName, "Arial"), runContainingTabToReplace.Elements(W.rPr), new XElement(W.t, leaderChar)); widthOfLeaderChar = CalcWidthOfRunInTwips(dummyRun); forceArial = true; } if (widthOfLeaderChar != 0) { var numberOfLeaderChars = (int)(Math.Floor((tabWidth * 1440) / widthOfLeaderChar)); if (numberOfLeaderChars < 0) numberOfLeaderChars = 0; span = new XElement(Xhtml.span, " " + "".PadRight(numberOfLeaderChars, leaderChar[0]) + " "); style.Add("margin", "0 0 0 0"); style.Add("padding", "0 0 0 0"); style.Add("width", string.Format("{0:0.00}in", tabWidth)); style.Add("text-align", "center"); if (forceArial) style.Add("font-family", "Arial"); } else { span = new XElement(Xhtml.span, " "); style.Add("margin", "0 0 0 0"); style.Add("padding", "0 0 0 0"); style.Add("width", string.Format("{0:0.00}in", tabWidth)); style.Add("text-align", "center"); if (leader == "underscore") { style.Add("text-decoration", "underline"); } } } else { #if false var bidi = element .Ancestors(W.p) .Take(1) .Elements(W.pPr) .Elements(W.bidi) .Where(b => b.Attribute(W.val) == null || b.Attribute(W.val).ToBoolean() == true) .FirstOrDefault(); var isBidi = bidi != null; if (isBidi) span = new XElement(Xhtml.span, new XEntity("#x200f")); // RLM else span = new XElement(Xhtml.span, new XEntity("#x200e")); // LRM #else span = new XElement(Xhtml.span, new XEntity("nbsp")); #endif style.Add("margin", string.Format("0 0 0 {0:0.00}in", tabWidth)); style.Add("padding", "0 0 0 0"); } span.AddAnnotation(style); return span; } } // Transform w:br to h:br. if (element.Name == W.br || element.Name == W.cr) { XElement span = null; var tabWidth = (decimal?)element.Attribute(PtOpenXml.TabWidth); if (tabWidth != null) { span = new XElement(Xhtml.span); var style = new Dictionary<string, string>(); style.Add("margin", string.Format("0 0 0 {0:0.00}in", tabWidth)); style.Add("padding", "0 0 0 0"); span.AddAnnotation(style); } var paragraph = element.Ancestors(W.p).FirstOrDefault(); bool isBidi = false; if (paragraph != null) { var bidi = paragraph .Elements(W.pPr) .Elements(W.bidi) .Where(b => b.Attribute(W.val) == null || b.Attribute(W.val).ToBoolean() == true) .FirstOrDefault(); isBidi = bidi != null; } var br = new XElement(Xhtml.br); XEntity zeroWidthChar = null; if (isBidi) zeroWidthChar = new XEntity("#x200f"); // RLM else zeroWidthChar = new XEntity("#x200e"); // LRM return new object[] { br, zeroWidthChar, span, }; } // Transform w:noBreakHyphen to '-' if (element.Name == W.noBreakHyphen) return new XText("-"); // Transform w:tbl to h:tbl. if (element.Name == W.tbl) { var style = new Dictionary<string, string>(); style.AddIfMissing("border-collapse", "collapse"); style.AddIfMissing("border", "none"); var bidiVisual = element.Elements(W.tblPr).Elements(W.bidiVisual).FirstOrDefault(); var tblW = element.Elements(W.tblPr).Elements(W.tblW).FirstOrDefault(); if (tblW != null) { var type = (string)tblW.Attribute(W.type); if (type != null && type == "pct") { var w = (int)tblW.Attribute(W._w); style.AddIfMissing("width", (w / 50).ToString() + "%"); } } var tblInd = element.Elements(W.tblPr).Elements(W.tblInd).FirstOrDefault(); if (tblInd != null) { var tblIndType = (string)tblInd.Attribute(W.type); if (tblIndType != null) { if (tblIndType == "dxa") { var width = (decimal?)tblInd.Attribute(W._w); if (width != null) { style.AddIfMissing("margin-left", string.Format("{0}pt", width / 20m)); } } } } XAttribute tableDirection = null; if (bidiVisual != null) { tableDirection = new XAttribute("dir", "rtl"); } else { tableDirection = new XAttribute("dir", "ltr"); } style.AddIfMissing("margin-bottom", ".001pt"); var table = new XElement(Xhtml.table, new XAttribute("border", "1"), new XAttribute("cellspacing", 0), new XAttribute("cellpadding", 0), tableDirection, element.Elements().Select(e => ConvertToHtmlTransform(wordDoc, settings, e, false, currentMarginLeft))); table.AddAnnotation(style); var jc = (string)element.Elements(W.tblPr).Elements(W.jc).Attributes(W.val).FirstOrDefault(); if (jc == null) jc = "left"; XAttribute dir = null; XAttribute jcToUse = null; if (bidiVisual != null) { dir = new XAttribute("dir", "rtl"); if (jc == "left") jcToUse = new XAttribute("align", "right"); else if (jc == "right") jcToUse = new XAttribute("align", "left"); else if (jc == "center") jcToUse = new XAttribute("align", "center"); } else { jcToUse = new XAttribute("align", jc); } var tableDiv = new XElement(Xhtml.div, dir, jcToUse, table); return tableDiv; } // Transform w:tr to h:tr. if (element.Name == W.tr) { var style = new Dictionary<string, string>(); int? trHeight = (int?)element.Elements(W.trPr).Elements(W.trHeight).Attributes(W.val).FirstOrDefault(); if (trHeight != null) style.AddIfMissing("height", string.Format("{0}in", (decimal)trHeight / 1440m)); var htmlRow = new XElement(Xhtml.tr, element.Elements().Select(e => ConvertToHtmlTransform(wordDoc, settings, e, false, currentMarginLeft))); if (style.Any()) htmlRow.AddAnnotation(style); return htmlRow; } // Transform w:tc to h:td. if (element.Name == W.tc) { var style = new Dictionary<string, string>(); XAttribute colSpan = null; XAttribute rowSpan = null; var tcPr = element.Element(W.tcPr); if (tcPr != null) { if ((string)tcPr.Elements(W.vMerge).Attributes(W.val).FirstOrDefault() == "restart") { var currentRow = element.Parent.ElementsBeforeSelf(W.tr).Count(); var currentCell = element.ElementsBeforeSelf(W.tc).Count(); var tbl = element.Parent.Parent; int rowSpanCount = 1; currentRow += 1; while (true) { var row = tbl.Elements(W.tr).Skip(currentRow).FirstOrDefault(); if (row == null) break; var cell2 = row.Elements(W.tc).Skip(currentCell).FirstOrDefault(); if (cell2 == null) break; if (cell2.Elements(W.tcPr).Elements(W.vMerge).FirstOrDefault() == null) break; if ((string)cell2.Elements(W.tcPr).Elements(W.vMerge).Attributes(W.val).FirstOrDefault() == "restart") break; currentRow += 1; rowSpanCount += 1; } rowSpan = new XAttribute("rowspan", rowSpanCount); } if (tcPr.Element(W.vMerge) != null && (string)tcPr.Elements(W.vMerge).Attributes(W.val).FirstOrDefault() != "restart") return null; if (tcPr.Element(W.vAlign) != null) { var vAlignVal = (string)tcPr.Elements(W.vAlign).Attributes(W.val).FirstOrDefault(); if (vAlignVal == "top") style.AddIfMissing("vertical-align", "top"); else if (vAlignVal == "center") style.AddIfMissing("vertical-align", "middle"); else if (vAlignVal == "bottom") style.AddIfMissing("vertical-align", "bottom"); else style.AddIfMissing("vertical-align", "middle"); } style.AddIfMissing("vertical-align", "top"); if ((string)tcPr.Elements(W.tcW).Attributes(W.type).FirstOrDefault() == "dxa") { decimal width = (int)tcPr.Elements(W.tcW).Attributes(W._w).FirstOrDefault(); style.AddIfMissing("width", string.Format("{0}pt", width / 20m)); } if ((string)tcPr.Elements(W.tcW).Attributes(W.type).FirstOrDefault() == "pct") { decimal width = (int)tcPr.Elements(W.tcW).Attributes(W._w).FirstOrDefault(); style.AddIfMissing("width", string.Format("{0:0.0}%", width / 50m)); } var tcBorders = tcPr.Element(W.tcBorders); GenerateBorderStyle(tcBorders, W.top, style, BorderType.Cell); GenerateBorderStyle(tcBorders, W.right, style, BorderType.Cell); GenerateBorderStyle(tcBorders, W.bottom, style, BorderType.Cell); GenerateBorderStyle(tcBorders, W.left, style, BorderType.Cell); CreateStyleFromShd(style, tcPr.Element(W.shd)); var gridSpan = (int?)tcPr.Elements(W.gridSpan).Attributes(W.val).Select(a => (int?)a).FirstOrDefault(); if (gridSpan != null) colSpan = new XAttribute("colspan", (int)gridSpan); } style.AddIfMissing("padding-top", "0in"); style.AddIfMissing("padding-bottom", "0in"); var cell = new XElement(Xhtml.td, rowSpan, colSpan, CreateBorderDivs(wordDoc, settings, element.Elements())); cell.AddAnnotation(style); return cell; } // Transform images if (element.Name == W.drawing || element.Name == W.pict || element.Name == W._object) { if (settings.ImageHandler == null) return null; return ProcessImage(wordDoc, element, settings.ImageHandler); } if (element.Name == W.sdt) { var relevantAncestors = element.Ancestors().TakeWhile(a => a.Name != W.txbxContent); var isRunLevelContentControl = relevantAncestors.Any(a => a.Name == W.p); if (isRunLevelContentControl) { var o = element.Element(W.sdtContent).Elements().Select(e => ConvertToHtmlTransform(wordDoc, settings, e, false, currentMarginLeft)) .ToList(); return o; } else { var o = CreateBorderDivs(wordDoc, settings, element.Element(W.sdtContent).Elements()); return o; } } if (element.Name == W.smartTag || element.Name == W.fldSimple) { var o = CreateBorderDivs(wordDoc, settings, element.Elements()); return o; } return null; } return null; }
private static void DetermineRunMarks(XElement run, XElement rPr, Dictionary<string, string> style, out XEntity runStartMark, out XEntity runEndMark) { runStartMark = null; runEndMark = null; // Only do the following for text runs. if (run.Element(W.t) == null) return; // Can't add directional marks if the font-family is symbol - they are visible, and display as a ? var addDirectionalMarks = true; if (style.ContainsKey("font-family")) { if (style["font-family"].ToLower() == "symbol") addDirectionalMarks = false; } if (!addDirectionalMarks) return; var isRtl = rPr.Element(W.rtl) != null; if (isRtl) { runStartMark = new XEntity("#x200f"); // RLM runEndMark = new XEntity("#x200f"); // RLM } else { var paragraph = run.Ancestors(W.p).First(); var paraIsBidi = paragraph .Elements(W.pPr) .Elements(W.bidi) .Any(b => b.Attribute(W.val) == null || b.Attribute(W.val).ToBoolean() == true); if (paraIsBidi) { runStartMark = new XEntity("#x200e"); // LRM runEndMark = new XEntity("#x200e"); // LRM } } }