Showing posts with label XDocument. Show all posts
Showing posts with label XDocument. Show all posts

Monday, June 20, 2011

Update an open XML word document in F#

 
I have created a small function in F# to update the content of a word document.
//reference to the package 
#r "WindowsBase"
//reference to the Xml and Linq 
#r "System.Xml"
#r "System.Xml.Linq"

open System
open System.IO
open System.IO.Packaging
open System.Xml
open System.Xml.Linq

//helper to create XName with a namespace
let xname str =
XName.Get(str, "http://schemas.openxmlformats.org/wordprocessingml/2006/main")

// the main function 
// changeDoc copies a word .docx document and updates the content by changing the xml that represents the content
let changeDoc oldPath newPath (updateDocument:XDocument -> XDocument) =
//update the package part
let updatePart (part:PackagePart) =
using (part.GetStream(FileMode.Open, FileAccess.Read)) (fun stream -> 
let xDocumentOut = stream |> XDocument.Load |> updateDocument
xDocumentOut.Save(part.GetStream(FileMode.Create, FileAccess.Write))
)

File.Copy(oldPath, newPath, true)
using (Package.Open(newPath, FileMode.Open, FileAccess.ReadWrite)) (fun package ->
let uri = new Uri("/word/document.xml", UriKind.Relative )

uri |> package.GetPart|> updatePart
)

// test function to update the document
// adds "_test" to every text  in the document.
let updateText (xDoc:XDocument) =
"t" |> xname  |> xDoc.Descendants |> Seq.iter (fun x -> x.Value <- x.Value + "_test")
xDoc

//test
changeDoc @"D:\Tmp\test.docx" @"D:\Tmp\test_copy.docx" updateText;;
Before "D:\Tmp\test.docx":
before
 
After "D:\Tmp\test_copy.docx":
after

Tuesday, May 31, 2011

Create in F# XDocument with XDeclaration and namespace

In this example I will create the following XML in F#:
<?xml version="1.0" encoding="utf-8"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:body>
    <w:p>
      <w:r>
        <w:t>This is a test</w:t>
      </w:r>
    </w:p>
  </w:body>
</w:document>
 
Transferring C#-code is not straightforward because the constructor of XDocument does not accept the following code: new  XDocument(new XDeclaration("1.0""utf-8""true"), new XElement("document"))

//First create some helpers:

let xnameNs str ns = XName.Get(str, ns)
let xname str =
    xnameNs str "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
 
let ns = XNamespace.Get("http://schemas.openxmlformats.org/wordprocessingml/2006/main")
 
let dec = new XDeclaration("1.0""utf-8""true")
 
let el =
    new XElement(xname "document",
        new XAttribute(XNamespace.Xmlns + "w", ns),
            new XElement(xname "body",
                new XElement(xname "p",
                    new XElement(xname "r",
                        new XElement(xname "t""This is a test")
                        ))))
 
//Add them together:
 
let document = 
    let doc =new XDocument(dec)
    doc.AddFirst(el)
    doc

//And test:
 
document.Save(@"D:\Tmp\test1.xml")

Total Pageviews