OpenXml操作Word的一些操作总结.无word组件生成word.

2023-10-27

OpenXml相对于用MS提供的COM组件来生成WORD,有如下优势:

1.相对于MS 的COM组件,因为版本带来的不兼容问题,及各种会生成WORD半途会崩溃的问题.

2.对比填满一张30多页的WORD来说(包含图,表等),用COM组件来生成会占用20秒,Openxml1秒.

3.MS Word软件太贵了,你的客户装的是开源WORD,如LibreOffice,OpenOffice.这样你就只能用Openxml生成的WORD文档,各种支持MS Word都能打开,避免客户机器上安装MS Word.

简单来说OpenXml的各个操作.

首先用OpenXml打开一张报表.

public void CreateOpenXMLFile(string filePath)  
        {  
            using (WordprocessingDocument objWordDocument = WordprocessingDocument.Create(filePath, WordprocessingDocumentType.Document))  
            {  
                MainDocumentPart objMainDocumentPart = objWordDocument.AddMainDocumentPart();  
                objMainDocumentPart.Document = new Document(new Body());  
                Body objBody = objMainDocumentPart.Document.Body;  
                //创建一些需要用到的样式,如标题3,标题4,在OpenXml里面,这些样式都要自己来创建的   
                //ReportExport.CreateParagraphStyle(objWordDocument);  
                SectionProperties sectionProperties = new SectionProperties();  
                PageSize pageSize = new PageSize();  
                PageMargin pageMargin = new PageMargin();  
                Columns columns = new Columns() { Space = "220" };//720  
                DocGrid docGrid = new DocGrid() { LinePitch = 100 };//360  
                //创建页面的大小,页距,页面方向一些基本的设置,如A4,B4,Letter,   
                //GetPageSetting(PageSize,PageMargin);  
  
                //在这里填充各个Paragraph,与Table,页面上第一级元素就是段落,表格.  
                objBody.Append(new Paragraph());  
                objBody.Append(new Table());  
                objBody.Append(new Paragraph());  
  
                //我会告诉你这里的顺序很重要吗?下面才是把上面那些设置放到Word里去.(大家可以试试把这下面的代码放上面,会不会出现打开openxml文件有误,因为内容有误)  
                sectionProperties.Append(pageSize, pageMargin, columns, docGrid);  
                objBody.Append(sectionProperties);  
                  
                //如果有页眉,在这里添加页眉.  
                if (IsAddHead)  
                {  
                    //添加页面,如果有图片,这个图片和上面添加在objBody方式有点不一样,这里搞了好久.  
                    //ReportExport.AddHeader(objMainDocumentPart, image);  
                }  
                objMainDocumentPart.Document.Save();  
            }  
        }  

发现上面有点注解说错,那个顺序不影响Word,但是影响如LibreOffice软件打开后看到的格式不正确.改里面太麻烦,直接在这说了.

从这个总纲里,把上面的各个步骤再来仔细说下.

首先是在Openxml创建标题3,标题4.

// 为文档创建段落样式  
        public static void CreateParagraphStyle(WordprocessingDocument doc)  
        {  
            // 进入文档控制样式部分  
            StyleDefinitionsPart styleDefinitionsPart;  
            styleDefinitionsPart = doc.MainDocumentPart.AddNewPart<StyleDefinitionsPart>();  
            Styles root = new Styles();  
            root.Save(styleDefinitionsPart);  
  
            Styles styles = styleDefinitionsPart.Styles;  
            if (styles == null)  
            {  
                styleDefinitionsPart.Styles = new Styles();  
                styleDefinitionsPart.Styles.Save();  
            }  
  
            Style style3 = CreateTitleStyle(3);  
            Style style4 = CreateTitleStyle(4);  
            // 把样式添加入文档中  
            styles.Append(style3);  
            styles.Append(style4);  
        }  
  
        private static Style CreateTitleStyle(int titleIndex)  
        {  
            string titleID = titleIndex.ToString();  
            string rsid = string.Empty;  
            string before = string.Empty;  
            string after = string.Empty;  
            string line = string.Empty;  
            string val = string.Empty;  
            int outline = titleIndex - 1;  
            if (titleIndex == 3)  
            {  
                rsid = "00BA1E98";  
                before = "130";//"260"  
                after = "0";  
                line = "286";//"416"  
                val = "32";  
  
            }  
            else if (titleIndex == 4)  
            {  
                rsid = "00BA1E98";  
                before = "88";  
                after = "0";  
                line = "288";//"376"  
                val = "28";  
            }  
  
            Style style2 = new Style() { Type = StyleValues.Paragraph, StyleId = titleID };  
            StyleName styleName2 = new StyleName() { Val = "heading " + titleID };  
            BasedOn basedOn1 = new BasedOn() { Val = "a" };  
            NextParagraphStyle nextParagraphStyle1 = new NextParagraphStyle() { Val = "a" };  
            LinkedStyle linkedStyle1 = new LinkedStyle() { Val = titleID + "Char" };  
            UIPriority uIPriority1 = new UIPriority() { Val = 9 };  
            PrimaryStyle primaryStyle2 = new PrimaryStyle();  
            Rsid rsid2 = new Rsid() { Val = rsid };  
            style2.Append(styleName2);  
            style2.Append(basedOn1);  
            style2.Append(nextParagraphStyle1);  
            style2.Append(linkedStyle1);  
            style2.Append(uIPriority1);  
            style2.Append(primaryStyle2);  
            style2.Append(rsid2);  
  
            StyleParagraphProperties styleParagraphProperties2 = new StyleParagraphProperties();  
            KeepNext keepNext1 = new KeepNext();  
            KeepLines keepLines1 = new KeepLines();  
            SpacingBetweenLines spacingBetweenLines1 = new SpacingBetweenLines() { Before = before, After = after, Line = line, LineRule = LineSpacingRuleValues.Auto };  
            OutlineLevel outlineLevel1 = new OutlineLevel() { Val = outline };  
            styleParagraphProperties2.Append(keepNext1);  
            styleParagraphProperties2.Append(keepLines1);  
            styleParagraphProperties2.Append(spacingBetweenLines1);  
            styleParagraphProperties2.Append(outlineLevel1);  
            style2.Append(styleParagraphProperties2);  
  
            StyleRunProperties styleRunProperties1 = new StyleRunProperties();  
            Bold bold1 = new Bold();  
            BoldComplexScript boldComplexScript1 = new BoldComplexScript();  
            // Kern kern2 = new Kern() { Val = (UInt32)44U };  
            FontSize fontSize2 = new FontSize() { Val = val };  
            FontSizeComplexScript fontSizeComplexScript2 = new FontSizeComplexScript() { Val = val };  
            styleRunProperties1.Append(bold1);  
            styleRunProperties1.Append(boldComplexScript1);  
            //styleRunProperties1.Append(kern2);  
            styleRunProperties1.Append(fontSize2);  
            styleRunProperties1.Append(fontSizeComplexScript2);  
            style2.Append(styleRunProperties1);  
            return style2;  
        }  

然后是对页面大小,页面方向,页距设置.(懒的和报表里的一个个对应,里面的页距有很多大家可以精确设置.)

public static void GetPageSetting(ref PageSize pageSize, ref PageMargin pageMargin)  
        {  
            bool val = IsPaperOrientation;  
            string str_paperSize = "Letter";//A4,B4  
            UInt32Value width = 15840U;  
            UInt32Value height = 12240U;  
            int top = 1440;  
            UInt32Value left = 1440U;  
            if (str_paperSize == "A4")  
            {  
                width = 16840U;  
                height = 11905U;  
            }  
            else if (str_paperSize == "B4")  
            {  
                width = 20636U;  
                height = 14570U;  
            }  
  
            if (!val)  
            {  
                UInt32Value sweep = width;  
                width = height;  
                height = sweep;  
  
                int top_sweep = top;  
                top = (int)left.Value;  
                left = (uint)top_sweep;  
            }  
  
            pageSize.Width = width;  
            pageSize.Height = height;  
            pageSize.Orient = new EnumValue<PageOrientationValues>(val ? PageOrientationValues.Landscape : PageOrientationValues.Portrait);  
  
            pageMargin.Top = top;  
            pageMargin.Bottom = top;  
            pageMargin.Left = left;  
            pageMargin.Right = left;  
            pageMargin.Header = (UInt32Value)720U;  
            pageMargin.Footer = (UInt32Value)720U;  
            pageMargin.Gutter = (UInt32Value)0U;  
        }  

然后重点来了,大家对各元素如何在OpenXml添加的.

我先说下,在Openxml里相关元素的关系,在Word里,按一下Enter,转一行,对应的一行元素就是Paragraph,那如果一行文字在里面如何存放.Paragraph->Run->Text,图表Paragraph->Run->Drawing,表格Table->TableRow->TableCell->Paragraph->Run->Text与Drawing.在关系上说,还是很简洁的.来看一下具体的操作,我们先定义一个类.对应OpenXML里的基本样式设置.

public class ReportCommon  
    {  
        public const float defaultSize = 12f;  
        public const float H1 = 20f;  
        public const float H3 = 16f;  
        public const float H4 = 14f;  
        private string text = string.Empty;  
  
        public ReportCommon()  
        {  
            Alignment = -1;  
            Size = defaultSize;  
        }  
  
        //规定-1左对齐,0中间,1右对齐  
        public int Alignment { get; set; }  
  
        public virtual float Size { get; set; }  
  
        public string Text { get; set; }  
  
        public virtual bool IsBold { get; set; }  
    }  

其中我定义这个类的三个子类,分别是ReportValue:主要是这种A: B,ReportImage:包含一个图片的路径.ReportText:只有一个文本.

private static List<Run> GetRuns(ReportCommon common)  
        {  
            List<Run> runs = new List<Run>();  
            if (common is ReportValue)  
            {  
                ReportValue reportvalue = common as ReportValue;  
                Run r = new Run();  
                RunProperties rP = GetRunProperties(reportvalue, true);  
                r.Append(rP);  
                string text = reportvalue.Text;  
                if (text.EndsWith(":"))  
                    text = text + " ";  
                if (!text.EndsWith(": "))  
                    text = text + ": ";  
                Text t = CreateText(text);  
                r.Append(t);  
                runs.Add(r);  
  
                r = new Run();  
                rP = GetRunProperties(reportvalue, false);  
                r.Append(rP);  
                r.Append(CreateText(reportvalue.Value));  
                runs.Add(r);  
            }  
            else if (common is ReportImage)  
            {  
                ReportImage reportImage = common as ReportImage;  
                Run r = new Run();  
                RunProperties rP = GetRunProperties(reportImage);  
                Drawing image = GetImageToBody(reportImage.RId, reportImage.Width * 600, reportImage.Height * 800);  
                //Drawing image = new Drawing();  
                //image.Append(new A.Blip() { Embed = new StringValue(reportImage.RId) });  
                r.Append(rP);  
                r.Append(image);  
                runs.Add(r);  
            }  
            else if (common is ReportText)  
            {  
                Run r = new Run();  
                RunProperties rP = GetRunProperties(common);  
                r.Append(rP);  
                r.Append(CreateText(common.Text));  
                runs.Add(r);  
            }  
            return runs;  
        } 

看了这里,问题是不是越来越多.图片具体操作先不说.上面的RunProperties,与CreateText分别是指什么.

RunProperties是指包含这段Text,你要设置的一些字体大小,颜色,文本对齐设置.

而CreateText是因为我们在Openxml你在后面加个空格,而会给你过滤掉,空格要对应到XML的具体设置,看如下代码.

public static RunProperties GetRunProperties(ReportCommon common, bool bBold = false)  
        {  
            RunProperties rPr = new RunProperties();  
            //Color color = new Color() { Val = "FF0000" }; // the color is red  
            RunFonts rFont = new RunFonts();  
            rFont.Ascii = "Arial"; // the font is Arial  
            //rPr.Append(color);  
            //rPr.Append(rFont);  
            if (common.IsBold || bBold)  
                rPr.Append(new Bold()); // it is Bold  
            //TextAlignment   
            rPr.Append(new FontSize() { Val = new StringValue((common.Size * 2).ToString()) }); //font size (in 1/72 of an inch)  
            return rPr;  
        }  
  private static Text CreateText(string text)  
        {  
            if (text == null)  
                text = string.Empty;  
            Text t = new Text(text);  
            if (text.EndsWith(" "))  
            {  
                t.Space = new EnumValue<SpaceProcessingModeValues>(SpaceProcessingModeValues.Preserve);  
            }  
            if (text.StartsWith(" "))  
            {  
                t.Space = new EnumValue<SpaceProcessingModeValues>(SpaceProcessingModeValues.Default);  
            }  
            return t;  
        }  

不知这么多代码大家看烦没,因为我这人喜欢不是业务与大纲的事,都喜欢直接看代码来说,比人讲的清楚.所以讲的时候也喜欢,直接上代码.废话不说了,说下图片的问题,Openxml插入图片比较麻烦,先贴一段代码.

private static Drawing GetImageToBody(string relationshipId, int x = 914400, int y = 360000)  
        {  
            // Define the reference of the image.  
            var element =  
                 new Drawing(  
                     new DW.Inline(  
                         new DW.Extent() { Cx = x, Cy = y },  
                         new DW.EffectExtent()  
                         {  
                             LeftEdge = 0L,  
                             TopEdge = 0L,  
                             RightEdge = 0L,  
                             BottomEdge = 0L  
                         },  
                         new DW.DocProperties()  
                         {  
                             Id = (UInt32Value)1U,  
                             Name = "Picture 1"  
                         },  
                         new DW.NonVisualGraphicFrameDrawingProperties(  
                             new A.GraphicFrameLocks() { NoChangeAspect = true }),  
                         new A.Graphic(  
                             new A.GraphicData(  
                                 new PIC.Picture(  
                                     new PIC.NonVisualPictureProperties(  
                                         new PIC.NonVisualDrawingProperties()  
                                         {  
                                             Id = (UInt32Value)0U,  
                                             Name = "New Bitmap Image.jpg"  
                                         },  
                                         new PIC.NonVisualPictureDrawingProperties()),  
                                     new PIC.BlipFill(  
                                         new A.Blip(  
                                             new A.BlipExtensionList(  
                                                 new A.BlipExtension()  
                                                 {  
                                                     Uri =  
                                                       "{28A0092B-C50C-407E-A947-70E740481C1C}"  
                                                 })  
                                         )  
                                         {  
                                             Embed = relationshipId,  
                                             CompressionState =  
                                             A.BlipCompressionValues.Print  
                                         },  
                                         new A.Stretch(  
                                             new A.FillRectangle())),  
                                     new PIC.ShapeProperties(  
                                         new A.Transform2D(  
                                             new A.Offset() { X = 0L, Y = 0L },  
                                             new A.Extents() { Cx = x, Cy = y }),  
                                         new A.PresetGeometry(  
                                             new A.AdjustValueList()  
                                         ) { Preset = A.ShapeTypeValues.Rectangle }))  
                             ) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" })  
                     )  
                     {  
                         DistanceFromTop = (UInt32Value)0U,  
                         DistanceFromBottom = (UInt32Value)0U,  
                         DistanceFromLeft = (UInt32Value)0U,  
                         DistanceFromRight = (UInt32Value)0U,  
                         EditId = "50D07946"  
                     });  
            // Append the reference to body, the element should be in a Run.  
            var blip = element.Descendants<DocumentFormat.OpenXml.Drawing.Blip>()  
               .FirstOrDefault<DocumentFormat.OpenXml.Drawing.Blip>();  
            return element;  
        } 

这段代码里,东东比较多,大家主要看这一节, Embed = relationshipId,也是参数里要求传入的,我们可以这么理解,在OpenXML插入一张电脑的图片,插入数据到word后,word然后把保存这个图片的一个标识量给我们,让我们来用,就是relationshipId.说到这,我们好像还没看如何把一张路径下的图片插入word.如下

public static void CreateImageRid(ReportImage reportImage, MainDocumentPart objMainDocumentPart)  
        {  
            ImagePartType imagetype = ImagePartType.Jpeg;  
            FileInfo newImg = new FileInfo(reportImage.Value);  
            ImagePart newImgPart = objMainDocumentPart.AddImagePart(imagetype);  
            //插入图片数据到Word里去.  
            using (FileStream stream = newImg.OpenRead())  
            {  
                newImgPart.FeedData(stream);  
            }  
            //Word返回给我们插入数据的标识符.  
            reportImage.RId = objMainDocumentPart.GetIdOfPart(newImgPart);  
        }  

这里图片插入有先后关系,要先调用上面这段,插入数据到word,然后才能调用上上段的那段代码来生成Drawing元素.

大家如果要把图片的宽度,设为当前Word的可用宽度.Int32Value width = (int)(pageSize.Width - pageMargin.Right - pageMargin.Left);

好吧,大家会发现上上段那里的长度特大,这里发现这里的值要很大才能显现比较好看的图片,一般我在原来的基础宽度*600,基础长度*800.原因吗,我也不清楚,有些猜测,没有验证就不说了,这个要求OpenXML生成报表比较急,我把这几天所有操作先总结一下.后面再来修改,如果有知道的道友,不妨说一下.

在这里,文字与图片如何生成Paragraph就很简单了.

public static Paragraph GetParagraph(ReportCommon common)  
        {  
            Paragraph p = new Paragraph();  
            ParagraphProperties pPr = GetParagraphProperties(common);  
            p.Append(pPr);  
            List<Run> run = GetRuns(common);  
            foreach (var r in run)  
            {  
                p.Append(r);  
            }  
            return p;  
        }  

好吧,最后说到如何在OpenXML生成一张表.生成图表我用的基础数据是List<List<string>>,上面的ReportTable数据就放在这个里面.当然还有一些基本的定义属性就不说.具体如下看代码.

public static Table GetParagraph(ReportTable reportTable, Int32Value width)  
        {  
            Table table = new Table();  
            TableProperties tblProp = new TableProperties(  
                new TableBorders(  
                    new TopBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 4 },  
                    new BottomBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 4 },  
                    new LeftBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 4 },  
                    new RightBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 4 },  
                    new InsideHorizontalBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 4 },  
                    new InsideVerticalBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 4 }  
                 )  
            );  
            tblProp.TableWidth = new TableWidth() { Width = width.ToString(), Type = TableWidthUnitValues.Dxa };  
            table.Append(tblProp);  
            int count = reportTable.Value.Count;  
            int cols = reportTable.Column;  
            int j = 0;  
            foreach (List<string> strs in reportTable.Value)  
            {  
                TableRow row = new TableRow();  
                for (int i = 0; i < cols; i++)  
                {  
                    TableCell cell = new TableCell();  
                    TableCellProperties tableCellProperties = new TableCellProperties();  
                    TableCellMargin margin = new TableCellMargin();  
                    margin.LeftMargin = new LeftMargin() { Width = "100", Type = TableWidthUnitValues.Dxa };  
                    margin.RightMargin = new RightMargin() { Width = "100", Type = TableWidthUnitValues.Dxa };  
                    tableCellProperties.Append(margin);  
                    Paragraph par = new Paragraph();  
                    Run run = new Run();  
                    if (j == 0 && reportTable.IsHaveColumn)  
                    {  
                        RunProperties rPr = new RunProperties();  
                        rPr.Append(new Bold());  
                        run.Append(rPr);  
                    }  
                    if (strs.Count != cols && i >= strs.Count - 1)  
                    {  
                        HorizontalMerge verticalMerge = new HorizontalMerge();  
                        if (i == strs.Count - 1)  
                        {  
                            RunProperties rPr = new RunProperties();  
                            rPr.Append(new Bold());  
                            run.Append(rPr);  
                            verticalMerge.Val = MergedCellValues.Restart;  
                            run.Append(CreateText(strs[i]));  
                        }  
                        else  
                        {  
                            verticalMerge.Val = MergedCellValues.Continue;  
                        }  
                        tableCellProperties.Append(verticalMerge);  
                    }  
                    else  
                    {  
                        run.Append(CreateText(strs[i]));  
                    }  
                    par.Append(run);  
                    cell.Append(tableCellProperties);  
                    cell.Append(par);  
                    row.Append(cell);  
                }  
                j++;  
                table.Append(row);  
            }  
  
            return table;  
        } 

代码可以简单的多,只是因为有一些要求,比如你表每行是5个数据,但是有一行,数据只有四个,有二个表格合并了,这里会默认把最后二格合并,具体意思大家可以改改代码看.

好吧,到这里,就差不多,元素添加完后,然后是把相关页面大小的设置加到objBody,最后是添加页眉. 


public static void AddHeader(MainDocumentPart mainDocPart, ReportImage reportImge)  
        {  
            // Delete the existing header parts.  
            mainDocPart.DeleteParts(mainDocPart.HeaderParts);  
  
            // Create a new header part and get its relationship id.  
            HeaderPart newHeaderPart = mainDocPart.AddNewPart<HeaderPart>();  
            string rId = mainDocPart.GetIdOfPart(newHeaderPart);  
              
            ImagePart imagepart = newHeaderPart.AddImagePart(ImagePartType.Jpeg);  
            FileInfo newImg = new FileInfo(reportImge.Value);  
            using (FileStream stream = newImg.OpenRead())  
            {  
                imagepart.FeedData(stream);  
            }  
            string imageRID = newHeaderPart.GetIdOfPart(imagepart);  
            reportImge.RId = imageRID;  
            Header header = GeneratePageHeaderPart(reportImge);  
            header.Save(newHeaderPart);  
              
            foreach (SectionProperties sectProperties in  
              mainDocPart.Document.Descendants<SectionProperties>())  
            {  
                //  Delete any existing references to headers.  
                foreach (HeaderReference headerReference in  
                  sectProperties.Descendants<HeaderReference>())  
                    sectProperties.RemoveChild(headerReference);  
                
                HeaderReference newHeaderReference =  
                  new HeaderReference() { Id = rId, Type = HeaderFooterValues.Default };  
                sectProperties.Append(newHeaderReference);  
            }  
            header.Save();  
        }  
  
        // Creates an header instance and adds its children.    
        private static Header GeneratePageHeaderPart(ReportImage reportImge)  
        {  
            var runs = GetRuns(reportImge);  
            Paragraph paragraph = new Paragraph();  
            paragraph.Append(GetParagraphProperties(reportImge));  
            foreach (var run in runs)  
            {  
                paragraph.Append(run);  
            }  
            paragraph.Append(new Run(new Text() { Text = "" }));  
            Header header = new Header();  
            header.Append(paragraph);  
            return header;  
        } 

上面的代码主要注意,Image所指的路径存放的和在前面的Document里不一样,这里存放在Header里,从Word文件解压来说,二都是不同的XML文档,你把图片数据写在Document里,得到的标识符在Header是空的.

好了.OpenXML的主要操作都在这了,但是大家如果想生成这种样式,应该如何处理?


上面每一个元素如Payload Mass (LBS): 0.22046,就是前面的ReportValue,如何以这种对齐方式来插入了?引入一个新的结构,ReportValueList,主要就是ReportValue的键表信息.

public static List<Paragraph> GetParagraph(ReportValueList valueList, Int32Value width, int column = 2)  
        {  
            if (column < 1)  
                column = 1;  
            List<Paragraph> list = new List<Paragraph>();  
            int currentcolumn = 0;  
            Paragraph currentParagraph = null;  
            foreach (var reportvalue in valueList.Values)  
            {  
                reportvalue.Size = valueList.Size;  
                if (currentcolumn == 0)  
                {  
                    currentParagraph = new Paragraph();  
                    ParagraphProperties pPr = new ParagraphProperties();  
                    //添加标签类  
                    Tabs tabs = new Tabs();  
                    Int32Value eachWidth = width / (new Int32Value(column));  
                    for (int i = 1; i < column; i++)  
                    {  
                        TabStop stop = new TabStop();  
                        stop.Val = new EnumValue<TabStopValues>(TabStopValues.Left);  
                        stop.Position = eachWidth * i;  
                        tabs.Append(stop);  
                    }  
                    pPr.Append(tabs);  
                    currentParagraph.Append(pPr);  
                    list.Add(currentParagraph);  
                }  
                List<Run> runs = GetRuns(reportvalue);  
                foreach (var run in runs)  
                {  
                    currentParagraph.Append(run);  
                }  
                currentcolumn++;  
                if (currentcolumn < column)  
                {  
                    Run run = new Run();  
                    run.Append(new TabChar());  
                    currentParagraph.Append(run);  
                }  
                if (currentcolumn >= column)  
                {  
                    currentcolumn = 0;  
                }  
            }  
            return list;  
        }

主要是对元素TabStop的运用,仔细的大家可以去查查文档

写到这里,忘记写要用到的命名空间.

using A = DocumentFormat.OpenXml.Drawing;  
using PIC = DocumentFormat.OpenXml.Drawing.Pictures;  
using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;  
using DocumentFormat.OpenXml;  
using DocumentFormat.OpenXml.Packaging;  
using DocumentFormat.OpenXml.Wordprocessing;  

这个就到这里了.下面如果有时间,我会讲一下,如果对整张报表来进行模版化,意思是在word里的每一个表,一个图片,一个文字,在软件上用生成的结果来替换相应的元素.



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenXml操作Word的一些操作总结.无word组件生成word. 的相关文章

  • ElasticSearch聚合查询返回结果buckets取值

    ElasticSearch聚合查询返回结果buckets取值 1 聚合查询如下 size 0 query bool must wildcard county company keyword wildcard 3 boost 1
  • Stm32-SysTick详解

    写在最前 本文是个人学习Stm32时所做笔记 没有写过C51 但学校学过 微机原理 但没学好 实验套件是正点原子Stm32zet6精英板 参考资料为正点原子所提供 本文所涉及代码均使用固件库 本文供自己日后需要时复习所用 同时希望可以给有需
  • 若依框架注册新用户,且赋角色

    若依框架注册新用户 且赋角色 若依官网 1 如何开启注册功能 开启前端注册开关 不管使用下那种方式开启注册功能 首先 先在前端里面views下找到login vue 将启注册开关先给设置为true 保存重启即可 如下图 2 两种开启新增用户
  • 【每日算法 && 数据结构(C++)】—— 06

    文章目录 01 题目描述 02 解题思路 03 代码片段 Time waits for no one cherish every moment 岁月不居 时光荏苒 珍惜每分每秒 01 题目描述 给你若干个有序链表 请将他们合并为一个有序的链
  • TP-LINK 路由器设置内网穿透

    TP LINK 路由器设置内网穿透 开发中经常遇到调用第三方软件回调调试的情况 例如微信开发 支付回调等测试 用内网穿透是一种简单的方式也是偷懒的方式 以TP LINK路由器为例实现内网穿透 登录路由器 2 找到路由器虚拟服务器 添加映射
  • tsconfig之forceConsistentCasingInFileNames属性

    文章来源 Wflynn forceConsistentCasingInFileNames 作用 是否强制代码中使用的模块文件名必须和文件系统中的文件名保持大小写一致 示例 假设我们有一个文件名为 FileManager ts 我们从这个文件
  • ECharts合并地图上的区域

    对于某些特定需求 官方下载的地图数据可能并不能完全满足 例如 要求显示中国地图 但需要将山东江苏和浙江这3个省合并起来 显示 东部区域 其他省份不变 于是就需要对官方提供的地图数据进行修改 一个思路是借助第三方工具 生成新区域的轮廓点 然后
  • 刷脸支付打造数字小镇应用的全新探索

    刷脸支付打造数字小镇是特色小镇数字化应用的一项全新探索 主要是依托一部手机游云南平台 在精准治理 惠民服务 生态宜居等领域进行数字化应用 丽江大研古城数字小镇启动建设以来已经取得初步成效 1月16日 从云南省发展和改革委员会举行的1月定时定
  • 28、宏任务与微任务

    原理图 setImmediate 也是宏任务 在 Node 环境下 微任务还有 process nextTick JS 中用来存储待执行回调函数的队列包含 2 个不同特定的列队 宏列队 用来保存待执行的宏任务 回调 比如 定时器回调 DOM
  • VMware Workstation 15虚拟机使用教程

    VMware Workstation 15虚拟机使用教程 前言 一 在虚拟机中安装win7 1 1新建虚拟机一个win7虚拟机 1 2插入虚拟机光盘 即指定ISO镜像文件 1 3设置虚拟机的BIOS 光驱为第一启动 1 4开始在虚拟机中安装
  • 数据库中的字段名与实体类中的属性名不能一一对应时的三种处理方式

    当查询结果的列名和java对象的属性名对应不上时需要采用下列方式进行处理 第一种方式 在查询语句中使用关键字 as 给列起别名 第二种方式 使用resultMap结果映射 第三种方式 开启驼峰命名自动映射 配置settings 实体类Car
  • Douglas-Peucker算法的Matlab实现

    代码 Douglas Peucker 道格拉斯 普克算法 function curve dpEdgeContour pnts clc clear A readmatrix EdgeContour1 xls Sheet 1 输入数据 x A
  • ES6系列教程第二篇--Iterator 详解

    一 什么是for of循环 对于如下一个数组 遍历其中的值方法有哪些 var arr a b c 首先想到的可能就是如下这种 这也是js最原始的遍历方法 和java的语法一样 var arr a b c for var i 0 i
  • 手写代码-Hudi-Demo

    import org apache hudi config HoodieIndexConfig import org apache hudi index HoodieIndex import org apache hudi DataSour
  • 托马斯推荐-android源码网站

    2019独角兽企业重金招聘Python工程师标准 gt gt gt http grepcode com 转载于 https my oschina net u 3407708 blog 1587258
  • js的简单数组去重

    介绍几种数组去重的方法 举例数组 const arr 1 1 2 2 null null undefined undefined new String 1 new String 1 a a NaN NaN set function uniq
  • 轮胎企业RFID生产线管理(MES系统)应用

    1 项目背景 在轮胎生产制造企业中 轮胎生产信息的正确采集和存储将对控制轮胎的生产过程 质量检验和质量跟踪等方面起着重要作用 目前 企业MES系统依靠手工记录和条码扫描的方式进行数据采集 由于轮胎生产工序多且复杂 半成品物料就有十几种工序
  • Spring整合Hibernate实现Spring Data JPA

    在上一篇文章 Spring整合Hibernate实现JPA持久化 中 我们已经介绍了怎样在Spring容器中合理地集成Hibernate来实现JPA的ORM机制 但是 细心的读者会发现 上一篇文章中使用了EntityManager来直接与数
  • UE4 更改DerivedDataCache 位置

    Epic Games UE 4 24 Engine Config BaseEngine ini InstalledDerivedDataBackendGraph MinimumDaysToKeepFile 7 Root Type KeyLe

随机推荐

  • OpenCV与Eigen (C++)【学习备忘】

    可点击OpenCV来自简书 OpenCV官网 OpenCV中的单位 棋盘格边长尺寸 mm 机器视觉 OPENCV 一 各个模块简介 二 数据类型与类对象 1 数据类型 点类 size类 向量类 矩形类 指针类 异常类等 2 类对象 2 1
  • maven资源

    http blog csdn net happyteafriends article details 7449642 jsp转换为静态页面参考 http blog csdn net zklxuankai article details 81
  • 最新Anaconda保姆级安装教程:手把手带你走进数据分析Anaconda安装门槛

    Python数据分析入门 基础概念和最新Anaconda安装 综述 什么是数据分析 数据分析是用适当的方法对收集来的大量数据进行分析 帮助人们作出判断 以便采取适当行动 mermaid svg lsc3TUoKjNk4ccj7 font f
  • 【Linux】—— vim常用操作命令

    这里写目录标题 1 vim的基本概念 2 命令模式的操作 光标跳转 剪贴复制 撤销修改 3 底行模式操作 4 配置vim编辑器 使用文件配置 快速配置 1 vim的基本概念 概念 vim重点解决代码编写的问题 本质文本编辑器 是具有多模式的
  • 简单搭建frp服务(服务端与客户端)

    记录搭建frp服务的过程 首先下载frp 本人使用的是0 22 0版本 其它版本可能不适用 可以通过wget命令进行下载 wget https github com fatedier frp releases download v0 22
  • ElacsticSearch中集合了分组、排序,求和,group by sort sum sum(A*B)

    最近做了一个项目 以前是mysql中 现在使用es进行查询 mysql的查询是 返回的结果是 1 字段求和的数据 2 字段相乘再求和在除数据 这个问题卡了一天 3 根据某个字段分组 4 根据某个字段排序 根据思路因为是求和 所以需要用到聚合
  • 消息 ByteBuf 详解

    Netty提供了ByteBuf来替代Java NIO的ByteBuffer缓冲区 以操纵内存缓冲区 与Java NIO的ByteBuffer相比 ByteBuf的优势如下 Pooling 池化 这点减少了内存复制和GC 提升了效率 复合缓冲
  • SpringBoot简介

    SpringBoot 第一部分 SpringBoot应用 相关概念 约定优于配置 约定优于配置 Convention over Configuration 又称按约定编程 是一种软件设计规范 本质上是对系统 类库或框架中一些东西假定一个大众
  • 微信小程序:以7天为周期,连续签到7天功能效果

    此功能以1 2 3 4 5 6 7这样为一周期 连续签到的功能 通过计算是否为整除7天计算 每7天后切换数目 从而改变周期表 本案例只是提供案例的基本操作 进一步涉及 每日用户集的监听 日历表 签到统计 连续签到 签到中断 后端数据处理 等
  • intellij idea 双击选中一个变量而不是单词

    在keymap 里搜索 select Word at caret 然后双击并在弹出选项里选add mouse shortcut 然后选double click 再在下面click pad 区域点一下 就可以和eclipse一样双击选中完整的
  • 查看权限linux文件权限

    查看权限 rw rw r 一共有10位数 其中 最前面那个 代表的是类型 中间那三个 rw 代表的是所有者 user 然后那三个 rw 代表的是组群 group 最后那三个 r 代表的是其他人 other 然后我再解释一下后面那9位数 r
  • 全国大学生软件测试大赛 Web性能测试--实例(一)

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 Web性能测试 实例 一 咪咕音乐测试 一 测试范围 二 测试要求 step1 a 操作流程 i 进入到咪咕音乐页面 点击 歌手 ii 对歌手进行筛选操作 点击红框内的任意按
  • 学习笔记:基于Transformer的时间序列预测模型

    1 一些准备的说明 为了便于读者理解 笔者将采取一个盾构机掘进参数预测的实际项目进行Transformer模型的说明 此外 该贴更多用于本人的学习记录 适合于对Transformer模型已经有一定了解的读者 此此次外 不定期更新中 一些参考
  • mybatisPlus分页查询的配置类

    SpringBoot中分页查询的配置类 Configuration public class MybatisPlusConfig Bean public MybatisPlusInterceptor mybatisPlusIntercept
  • 计算机视觉服务系统

    tornado教程HTTP教程 Eureka教程Eureka1Eureka2
  • Colossal-AI的安装

    最近在学习stable diffusion model 但是这个模型成本比较高 作为低端学习者 借助colossal ai加速训练 即能满足显卡要求又能节约时间 Colossal AI 是一个集成的大规模深度学习系统 具有高效的并行化技术
  • 二叉树变成搜索二叉树

    给你一个普通的二叉树 把它变成搜索二叉树 要求不改变这个树的结构 例如 给你如下二叉树 10 2 7 8 4 结果是 8 4 10 2 7 思路 1 中序遍历该二叉树 把结果存在临时数组 arr 中 2 对 arr 进行排序 3 把 arr
  • C++(11):true_type, false_type

    true type和false type是integral constant实例化的别名 C 11 integral constant 风静如云的博客 CSDN博客 template
  • matlab机械手ikine函数,matlab机器人工具箱10.1(有函数说明)

    实例简介 机器人工具箱10 1版 有例子可以学习 希望对大家有所帮助 实例截图 核心代码 robot工具箱 V10 1有例子 robot工具箱10 1及例子 matlab robot V10 1工具箱 pdf rvctools common
  • OpenXml操作Word的一些操作总结.无word组件生成word.

    OpenXml相对于用MS提供的COM组件来生成WORD 有如下优势 1 相对于MS 的COM组件 因为版本带来的不兼容问题 及各种会生成WORD半途会崩溃的问题 2 对比填满一张30多页的WORD来说 包含图 表等 用COM组件来生成会占