Skip to content
This repository has been archived by the owner on Nov 16, 2023. It is now read-only.

DocumentFormat.OpenXml.WordProcessing namespace .NET wrappers #86

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

niku-live
Copy link
Contributor

@niku-live niku-live commented Jul 18, 2018

In our add-on we do lots of existing Word documents modification and usually we use DocumentFormat.OpenXml library for that. I think some kind of direct OpenXml document modification is really needed in NAV. At least for us this is very important.

This commit contains wrappers for various Word document creation / modification tasks. Basically I tried to expose enough .NET classes to be able to do the following:

There are a few points I need to explain that might conflict with Open C/AL Library commit requirements:

  • Some wrappers depend on helper codeunit "OpenXml DotNet Helper". I needed this to call generic .NET methods like AddPart. I could copy the same code to every place I needed it but I decided to move generics handling to helper codeunit. If that makes any problems, I can return to code dublication.
  • OpenXml .NET library has such types as StringValue, Int32Value and so on that wraps basic .NET types to OpenXml types. I decided not to create NAV wrappers for such types. If some class has a property of such type and I need to create a setter procedure for it, as a parameter I use simple type (Text, Integer, Boolean) and assign property indirectly (for example look at Codeunit "DotNet_Word.Style" procedure "SetBasedOn").
  • I added "Word." prefix in all wrapper codeunits name. I did this because DocumentFormat.OpenXml.Wordprocessing namespace contains some classes that have the same name as some .NET classes from mscorlib. This helps avoiding conflict in names.
  • Codeunit "DotNet_Word.Text" has a very strange code in Create procedure. This is because I cannot call this class constructor directly - constructor has the same name as method in this class and NAV compiler resolves name to a method and not to a constructor. So to overcome this NAV limitation, I used reflection.
  • Codeunit "DotNet_Wordprocessing" uses MemoryStream internally (so it is not just a simple wrapper). I need this because both InStream and OutStream are one-way only and Wordprocessing.Open method need two-way stream. So wrapper has Open procedure which accepts InStream, copies it to MemoryStream and all modifications are done here, then there is Save procedure which accepts OutStream and copies MemoryStream content to it. So it conflicts simple wrapper idea, but I think this is the right way to go, since we do not have two-way stream.

@grobyns
Copy link

grobyns commented Jul 20, 2018

Hi,

thanks for your submission. We'll review the code, but as this is a rather large pr it will take some time to go through it all.

cheers,
Gert

BaseApp/COD50018.TXT Outdated Show resolved Hide resolved
BaseApp/COD50018.TXT Outdated Show resolved Hide resolved
@JesperSchulz
Copy link
Contributor

JesperSchulz commented Nov 15, 2018

We haven't forgot this one, but we're currently looking into a larger effort to expose a few, much used, .NET libraries. OpenXML is part of that effort and there hence is quite some overlap. A little more patience, while we make sure we cover your needs and avoid duplicate functionality.

@niku-live
Copy link
Contributor Author

Good to hear that this wasn't forgotten :).

While I don't know how much of OpenXML functionality you are planning to expose, let me iterate through cases where we need OpenXML in our add-ons (I hope that this will give at least one partner view on what is useful OpenXML functionality in NAV and what not):

  1. We use OpenXML for custom Word based report generation. While it is possible to generate Word file using standard NAV reporting functionality in most cases it is not enough. So what we need is a possibility to programmatically create Word file (or modify existing), create paragraphs, format text, add tables, pictures, numbering and bullets, change headings and similar modification. This PR basically illiustrates most important points of our needs.
  2. We use OpenXML for custom Excel based report generation. While it is possible to generate Excel file using standard NAV reporting or Excel buffer functionality in most cases it is not enough. What existing functionality lacks are possibility to modify existing Excel file including formatting, page options, headers and footers, sheet names modification, borders and shading, width and height of columns and rows.
  3. We use OpenXML for existing Excel or Word file password protection (for example to password protect documents generated using standard NAV reporting functionality). This is very important when you need to automate document sending via E-mail because usually clients require files to be somehow password protected.
  4. We use OpenXML for importing data from Word. While such cases might look specific, it is not - you can create tables in Word and put data there, so it is natural question from client why it cannot be imported. And in fact it is simple if you can access file elements using OpenXNL
  5. We also use OpenXML for advanced data import from Excel. Usually standard Excel buffer functionality is enough, but there are cases when you need to know additional data about cell (for example is cell colored).
  6. We you comments in both Excel and Word to annotate path of the data and give additional information, so we need to create comments programatically.
  7. In both Excel and Word files we need to merge cells programatically to make document look better.

To tell you the truth, before ".NET forbidden" policy came into light we were using ClosedXML library for most cases as it is very good OpenXML wrapper that makes OpenXML more useful (for example ClosedXML has AutoFit functionality implemented and while it is not perfect it works without any need for Excel). So if you are looking into exposing OpenXML I definitely recommend to review ClosedXML approach to how OpenXML can be wrapped in a good way.

Finally one more point from me - as I mentioned in a lot of cases we need to password protect documents generated from NAV, while DOCX and XLSX files can be password protected using OpenXML, it is different cases for PDF and ZIP - we used PdfSharp for PDF file protection and Ionic.Zip for ZIP file protection. Sending unprotected file to external service (AzureFunction) to add password protection seems illogical so while considering what to expose and what not please think about this as well (it is also possible to add ZIP file protection functionality and all other files just wrap in ZIP, but then at least ZIP password protection is needed).

@marknitek
Copy link

@JesperSchulz any news on this? We have a solution that uses openxml to create custom xml parts that we then insert into documents in content controls for updatable word documents. Before we move all that logic to azure functions or anything, it would be nice to know what the plans are for openxml integration in AL.

@JesperSchulz
Copy link
Contributor

@marknitek, I'm afraid we're not able to move forward with this wrapper at the moment. Priority is currently on moving to al. Once the move is completed, we can add more capabilities to the language rather than adding these kind of wrappers - at least that is the thinking. I understand that there is a rather big need for a solution such as the one suggested here, but I don't know when we'll be able to provide a solution, and what that solution looks like. I will bring up this wrapper in the one of the coming planning meetings again, but resources are currently quite booked with all sorts of important tasks related to the big move.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants