texto procesamiento open office documento documentformat c# .net automation ms-word openxml

c# - procesamiento - Insertar OpenXmlElement después del marcador de palabras en Open XML SDK



documentformat.openxml.dll download (1)

Código

Una vez que tenga el marcador, puede acceder a su elemento padre y agregar los otros elementos después de él.

using (WordprocessingDocument document = WordprocessingDocument.Open(@"C:/Path/filename.docx", true)) { var mainPart = document.MainDocumentPart; var res = from bm in mainPart.Document.Body.Descendants<BookmarkStart>() where bm.Name == "BookmarkName" select bm; var bookmark = res.SingleOrDefault(); if (bookmark != null) { var parent = bookmark.Parent; // bookmark''s parent element // simple paragraph in one declaration //Paragraph newParagraph = new Paragraph(new Run(new Text("Hello, World!"))); // build paragraph piece by piece Text text = new Text("Hello, World!"); Run run = new Run(new RunProperties(new Bold())); run.Append(text); Paragraph newParagraph = new Paragraph(run); // insert after bookmark parent parent.InsertAfterSelf(newParagraph); var table = new Table( new TableProperties( new TableStyle() { Val = "TableGrid" }, new TableWidth() { Width = 0, Type = TableWidthUnitValues.Auto } ), new TableGrid( new GridColumn() { Width = (UInt32Value)1018U }, new GridColumn() { Width = (UInt32Value)3544U }), new TableRow( new TableCell( new TableCellProperties( new TableCellWidth() { Width = 0, Type = TableWidthUnitValues.Auto }), new Paragraph( new Run( new Text("Category Name")) )), new TableCell( new TableCellProperties( new TableCellWidth() { Width = 4788, Type = TableWidthUnitValues.Dxa }), new Paragraph( new Run( new Text("Value")) )) ), new TableRow( new TableCell( new TableCellProperties( new TableCellWidth() { Width = 0, Type = TableWidthUnitValues.Auto }), new Paragraph( new Run( new Text("C1")) )), new TableCell( new TableCellProperties( new TableCellWidth() { Width = 0, Type = TableWidthUnitValues.Auto }), new Paragraph( new Run( new Text("V1")) )) )); // insert after new paragraph newParagraph.InsertAfterSelf(table); } // close saves all parts and closes the document document.Close(); }

El código anterior debería hacerlo. Sin embargo, explicaré algunas circunstancias especiales.

Tenga en cuenta que intentará las inserciones después del elemento principal del marcador. ¿Qué comportamiento espera si su marcador es parte de un párrafo dentro de una tabla? ¿Debería anexar el nuevo párrafo y la tabla inmediatamente después de esa tabla? ¿O debería hacerlo después de esa mesa?

Es posible que se pregunte por qué las preguntas anteriores importan. Todo depende de dónde ocurrirá la inserción. Si el elemento primario del marcador está en una tabla, actualmente el código anterior intentará colocar una tabla dentro de una tabla. Eso está bien, sin embargo, puede ocurrir un error debido a una estructura inválida de OpenXml. La razón es que si la tabla insertada fue el último elemento en TableCell de la tabla original, es necesario que se agregue un elemento Párrafo después de la etiqueta de cierre de TableCell. Pronto descubrirá este problema si ocurrió una vez que intentó abrir el documento en MS Word.

La solución es determinar si realmente está realizando la inserción dentro de una tabla.

Para hacerlo, podemos agregar al código anterior (después de la var padre):

var parent = bookmark.Parent; // bookmark''s parent element // loop till we get the containing element in case bookmark is inside a table etc. // keep checking the element''s parent and update it till we reach the Body var tempParent = bookmark.Parent; bool isInTable = false; while (tempParent.Parent != mainPart.Document.Body) { tempParent = tempParent.Parent; if (tempParent is Table && !isInTable) isInTable = true; } // ... newParagraph.InsertAfterSelf(table); // from above sample // if bookmark is in a table, add a paragraph after table if (isInTable) table.InsertAfterSelf(new Paragraph());

Eso debería evitar que ocurra el error y darle un OpenXml válido. La idea del ciclo while se puede usar si respondió "sí" a mi pregunta anterior y deseaba realizar la inserción después de la tabla principal en lugar de dentro de la tabla como haría el código anterior. Si ese es el caso, el problema anterior ya no sería una preocupación y puede reemplazar ese bucle y booleano con lo siguiente:

var parent = bookmark.Parent; // bookmark''s parent element while (parent.Parent != mainPart.Document.Body) { parent = parent.Parent; }

Esto sigue reasignando al padre hasta que sea el elemento principal que lo contiene en el nivel del Cuerpo. Entonces, si el marcador estaba en un párrafo que estaba en una tabla, pasaría de Párrafo a TableCell a TableRow a Table y se detendría allí ya que el padre de Table es el Cuerpo. En ese punto elemento parent = Table y podemos insertarlo después.

Eso debería abarcar algunos enfoques diferentes, según su intención original. Avíseme si necesita alguna aclaración después de probarlo.

Reflector de documentos

Es posible que se pregunte cómo determiné los valores de GridColumn.Width . Hice una tabla y usé la herramienta Reflector de documentos para obtenerla. Cuando instaló Open Xml SDK, las herramientas de productividad (si las instaló) se ubicarían en C:/Program Files/Open XML Format SDK/V2.0/tools (o similar).

La mejor forma de aprender cómo funciona el formato * .docx (o cualquier documento con formato Open Xml) es abrir un archivo existente con la herramienta Document Reflector. Navegue por la parte del documento y ubique los elementos que desea replicar. La herramienta muestra el código real utilizado para generar el documento completo. Este es un código que puedes copiar / pegar en tu aplicación para generar resultados similares. Puede ignorar todos los ID de referencia por lo general; Tendrás que echarle un vistazo y probarlo para tener una idea.

Como mencioné, el código de la tabla anterior se adaptó a partir de un documento de muestra. Agregué una tabla simple a un docx, luego la abrí en la herramienta y copié el código generado por la herramienta (eliminé algunos extras para limpiarlo). Eso me dio una muestra de trabajo para agregar una tabla.

Es especialmente útil cuando desea saber cómo escribir código que genera algo, como tablas formateadas y párrafos con estilos, etc.

Eche un vistazo a este enlace para obtener capturas de pantalla e información sobre las otras herramientas incluidas en el SDK: una introducción a Open XML SDK 2.0 .

Fragmentos de código

También podría estar interesado en los fragmentos de código para Open Xml. Para ver una lista de fragmentos, consulte esta publicación en el blog . Puede descargarlos desde aquí: 2007 Office System Sample: Open XML Format SDK 2.0 Snippets de código para Visual Studio 2008 .

Una vez instalado, los agregará desde Herramientas | Menú Administrador de fragmentos de código. Seleccione C # para el idioma, haga clic en el botón Agregar y navegue a PersonalFolder / Visual Studio 2008 / Code Snippets / Visual C # / Abra XML SDK 2.0 para Microsoft Office para agregarlos. Desde su código, haga clic derecho y seleccione "Insertar fragmento" y seleccione el que desee.

Pude acceder a un marcador en mi documento de Word usando este código:

var res = from bm in mainPart.Document.Body.Descendants<BookmarkStart>() where bm.Name == "BookmarkName" select bm;

Ahora quiero insertar un párrafo y una tabla después de este marcador. ¿Cómo puedo hacer eso? (Código de ejemplo sería apreciado)