none
Open input.docx, find & replace some strings then save as output.doc RRS feed

  • Question

  • This has been driving me to distraction, all I need to do is open a template document on the webserver and fill in the information provided by an Intranet user i.e. Address/ Name/ Quote Number.

    Then save this document to another server under a folder called ‘Quote’

    Then give them a link to this new quote file.

    Sounds really easy, but to do it has been one of the most frustrating things I have ever done with asp.net (VB code-behind)

    I have tried the word interop, runs find on my machine but on the webserver complete fail, I know all about MS saying it must interact with the desktop and the security issues and all the rest, spent a good week on this and have now given up.

    So I though I would try Open XML instead, I am Lost.

    Here are some bits that I have cobbled together but just can’t see how to tie them all together.

    **********************Tasks to do**************************

    Open a document saved in a folder off the root of the website

    find and replace 'Address'

    Find and Replace 'CustomerName'

    find and replace 'QuoteNo'

    Save document to a path Quote with it's filename being the Quotenumber.doc/docx

    **********************************************************

    Coded help would be most appreciated by any of you in the know.

    Imports Microsoft.VisualBasic
    Imports System.IO
    Imports System.Xml
    Imports DocumentFormat.OpenXml
    Imports DocumentFormat.OpenXml.Packaging
    'Imports DocumentFormat.OpenXml.Wordprocessing
    Imports System
    Imports System.Text
    Imports System.Windows.Forms
    Public Class Openxml
        Dim wdDoc As WordprocessingDocument
        Dim mainPart As MainDocumentPart
        Dim xdoc As XmlDocument
        Dim docText As String = Nothing
        Dim nsManager As XmlNamespaceManager
        Dim nodes As XmlNodeList = Nothing
        Public Function OpenFile(Filename As String) As String
            OpenFile = ""
            Dim wordmlNamespace As String = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
            wdDoc = WordprocessingDocument.Open(Filename, True)
            ' Manage namespaces to perform Xml XPath queries.
            Dim nt As NameTable = New NameTable
            nsManager = New XmlNamespaceManager(nt)
            nsManager.AddNamespace("w", wordmlNamespace) '
            ' Get the document part from the package.
            xdoc = New XmlDocument(nt)
            ' Load the XML in the part into an XmlDocument instance
            xdoc.Load(wdDoc.MainDocumentPart.GetStream)
            'If System.IO.File.Exists(Filename) = True Then
            '    wdDoc = WordprocessingDocument.Open(Filename, True)
            '    Dim sr As StreamReader = New StreamReader(wdDoc.MainDocumentPart.GetStream)
            '    Using (sr)
            '        docText = sr.ReadToEnd
            '    End Using
            'Else
            '    OpenFile = "File:" & Filename & " does not exist!!"
            'End If
        End Function
        Public Function SaveFile(Filename As String) As String
            SaveFile = ""
            Try
                'If System.IO.File.Exists(Filename) = True Then
                '    ' Delete Existing file
                '    System.IO.File.Delete(Filename)
                'End If
                'wdDoc.Save("OutDocument.docx", FormatType.Word2007)
                'wdDoc.
                'Dim wordDoc As WordprocessingDocument = WordprocessingDocument.Create(Filename, WordprocessingDocumentType.Document)
                'Dim mainPart As MainDocumentPart = wordDoc.AddMainDocumentPart
                'Dim sw As StreamWriter = New StreamWriter(wdDoc.MainDocumentPart.GetStream(FileMode.Create))
                'Using (sw)
                '    sw.Write(docText)
                'End Using
            Catch ex As Exception
            End Try
        End Function
        Public Function ReplaceText(FindThis As String, ReplaceWithThis As String) As String
            ReplaceText = ""
            ' Get the text nodes in the document.
            If nodes Is Nothing Then
                nodes = xdoc.SelectNodes("//w:t", nsManager)
            End If
            Dim node As XmlNode
            Dim nodeText As String = ""
            ' Make the swap.
            For Each node In nodes
                nodeText = node.FirstChild.InnerText
                If (InStr(nodeText, FindThis) > 0) Then
                    'nodeText = nodeText.Replace(FindThis, ReplaceWithThis)
                    node.FirstChild.InnerText = nodeText.Replace(FindThis, ReplaceWithThis)
                End If
            Next
            Dim wordDoc2 As WordprocessingDocument = WordprocessingDocument.Open("c:\text.docx", True)
            Using (wordDoc2)
                Dim themePart1 As ThemePart = wdDoc.MainDocumentPart.ThemePart
                Dim themePart2 As ThemePart = wordDoc2.MainDocumentPart.ThemePart
                Dim streamReader As StreamReader = New StreamReader(themePart1.GetStream())
                Dim streamWriter As StreamWriter = New StreamWriter(themePart2.GetStream(FileMode.Create))
                Using (streamWriter)
                    streamWriter.Write(streamReader.ReadToEnd)
                End Using
            End Using
            'xdoc.Save(
            ' Write the changes back to the document.
            'xdoc.Save(wdDoc.MainDocumentPart.GetStream(FileMode.Create))
            'Try
            '    Dim regexText As Regex = New Regex(FindThis)
            '    docText = regexText.Replace(docText, ReplaceWithThis)
            'Catch ex As Exception
            '    ReplaceText = "Search term not found!!<br>" & ex.Message
            'End Try
        End Function
    End Class

    Tuesday, April 24, 2012 1:10 PM

Answers

  • Not the way I wanted to do it but it works just as well.

        Protected Function PostDocument(QuoteNumber As String, FileName As String) As Boolean
            PostDocument = False
            ' Get all Required Information
            Dim ShortCustomerName As String = Mid(Txb_Individual.Text.Trim, 1, InStr(Txb_Individual.Text, " ") - 1)
            Dim FormalCustomerName As String = Mid(Txb_Individual.Text.Trim, 1, 1).ToUpper & "." & Mid(Txb_Individual.Text.Trim, InStr(Txb_Individual.Text.Trim, " ") + 1, 1).ToUpper & Mid(Txb_Individual.Text.Trim, InStr(Txb_Individual.Text.Trim, " ") + 2).ToLower
            ' Get class up and runing
            Dim EditWord As New Openxml()
            ' Copy Template file
            Try
                File.Copy(MapPath("workingfiles/quotes.dotx"), MapPath("workingfiles/" & FileName))
            Catch ex As Exception
                Lab_Error.Text = "Oops unable to create Quote file:" & MapPath("workingfiles/" & FileName) & "<br>Error:" & ex.Message
                Exit Function
            End Try
            ' Open document
            Dim OpenDoc As String = EditWord.OpenFile(MapPath("workingfiles/" & FileName))
            If OpenDoc = "" Then
                Dim results As String = ""
                ' Do word replacment
                EditWord.ReplaceText("Company", Txb_Company.Text.Trim)
                Dim CustomerAddress() As String = Split(GetCustomerAddress(Txb_Company.Text.Trim), "|")
                For i As Integer = 1 To 5
                    If i - 1 <= UBound(CustomerAddress) Then
                        EditWord.ReplaceText("Ad" & i, CustomerAddress(i - 1).Trim)
                    Else
                        EditWord.ReplaceText("Ad" & i, "")
                    End If
                Next
                EditWord.ReplaceText("FAO", "Attn. " & FormalCustomerName)
                EditWord.ReplaceText("PeakQuote", QuoteNumber)
                EditWord.ReplaceText("Today", Now.Date.ToLongDateString)
                EditWord.ReplaceText("Name", ShortCustomerName)
                EditWord.ReplaceText("User", Replace(Request.Cookies("ITR")("FullUserName").ToString, "+", " "))
                ' Save the new Quote to were the user expects it to be.
                Dim SaveDov As String = EditWord.SaveFile("\\engineering4\quote\" & FileName)
                If SaveDov <> "" Then
                    Lab_Error.Text = SaveDov
                    Exit Function
                End If
                Try
                    File.Copy(MapPath("workingfiles/" & FileName), "\\engineering4\quote\" & FileName)
                    File.Delete(MapPath("workingfiles/" & FileName))
                    ' Set flag to show processing was all OK
                    PostDocument = True
                Catch ex As Exception
                    Lab_Error.Text = ex.Message
                End Try
            Else
                Lab_Error.Text = OpenDoc
            End If
        End Function

    One thing to note for anybody else, you can’t ‘Search and Replace’ well replace with a string containing vbCrLf as you are editing the xml direct and to get new lines you would have to create new sections for each line.

    I did it the simple way (cop-out) as you can see around the customer Address with Ad1,2,3,4,5

    Anyway all in and working now.

    Thanks all.


    A picture paints a thousand words, a Video has thousands of pictures All help files should be shown as videos.

    • Marked as answer by Born59 Thursday, April 26, 2012 9:39 AM
    Thursday, April 26, 2012 9:39 AM

All replies

  • OK, still no answers :-(

    Been working on this a bit more, here is the App_Code (class)

    Imports Microsoft.VisualBasic Imports System.IO Imports System.Xml Imports DocumentFormat.OpenXml Imports DocumentFormat.OpenXml.Packaging Imports DocumentFormat.OpenXml.Wordprocessing Imports System Imports System.Text Public Class Openxml Dim wdDoc As WordprocessingDocument Dim mainPart As MainDocumentPart Dim xdoc As XmlDocument Dim docText As String = Nothing Dim nsManager As XmlNamespaceManager Dim nodes As XmlNodeList = Nothing Public Function OpenFile(Filename As String) As String OpenFile = "" If System.IO.File.Exists(Filename) = True Then wdDoc = WordprocessingDocument.Open(Filename, True) ' Manage namespaces to perform Xml XPath queries. Dim nt As NameTable = New NameTable nsManager = New XmlNamespaceManager(nt) nsManager.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main") ' Get the document part from the package. xdoc = New XmlDocument(nt) ' Load the XML in the part into an XmlDocument instance xdoc.Load(wdDoc.MainDocumentPart.GetStream) Else OpenFile = "File:" & Filename & " does not exist!!" End If End Function Public Function SaveFile(Filename As String) As String SaveFile = "" Try 'If System.IO.File.Exists(Filename) = True Then ' ' Delete Existing file ' System.IO.File.Delete(Filename) 'End If ' Write the changes back to the document. xdoc.Save(wdDoc.MainDocumentPart.GetStream(FileMode.Create)) wdDoc.Close() wdDoc = Nothing Catch ex As Exception SaveFile = "Unable to save file:" & Filename & "<br>Error:" & ex.Message End Try End Function Public Sub ReplaceText(FindThis As String, ReplaceWithThis As String) ' Get the text nodes in the document. If nodes Is Nothing Then nodes = xdoc.SelectNodes("//w:t", nsManager) End If Dim node As XmlNode Dim nodeText As String = "" ' Make the swap. For Each node In nodes nodeText = node.FirstChild.InnerText If (InStr(nodeText, FindThis) > 0) Then 'nodeText = nodeText.Replace(FindThis, ReplaceWithThis) node.FirstChild.InnerText = nodeText.Replace(FindThis, ReplaceWithThis) Exit For End If Next End Sub End Class


    And here is the call from the web page, have cut some irrelevant stuff out

    Imports System.IO
    Imports System.Data
    Imports System.Data.SqlClient
    Imports Openxml
    Partial Class _pullquoteno2
        Inherits System.Web.UI.Page
        Protected Function PostDocument(QuoteNumber As String, FileName As String) As Boolean
            PostDocument = False
            ' Get all Required Information
            Dim CustomerAddress As String = Txb_Company.Text.Trim & vbCrLf & GetCustomerAddress(Txb_Company.Text.Trim)
            Dim ShortCustomerName As String = Mid(Txb_Individual.Text.Trim, 1, InStr(Txb_Individual.Text, " ") - 1)
            Dim FormalCustomerName As String = Mid(Txb_Individual.Text.Trim, 1, 1).ToUpper & "." & Mid(Txb_Individual.Text.Trim, InStr(Txb_Individual.Text.Trim, " ") + 1, 1).ToUpper & Mid(Txb_Individual.Text.Trim, InStr(Txb_Individual.Text.Trim, " ") + 2).ToLower
            ' Get class up and runing
            Dim EditWord As New Openxml()
            ' Open document
            Dim OpenDoc As String = EditWord.OpenFile(MapPath("workingfiles/quotes.docx"))
            If OpenDoc = "" Then
                Dim results As String = ""
                ' Do word replacment
                EditWord.ReplaceText("Address", Replace(CustomerAddress, vbCrLf & vbCrLf, vbCrLf))
                EditWord.ReplaceText("FAO", "Attn. " & FormalCustomerName)
                EditWord.ReplaceText("peakquote", QuoteNumber)
                EditWord.ReplaceText("today", Now.Date.ToLongDateString)
                EditWord.ReplaceText("name", ShortCustomerName)
                EditWord.ReplaceText("user", Replace(Request.Cookies("ITR")("FullUserName").ToString, "+", " "))
                ' Save the new Quote to were the user expects it to be.
                Dim SaveDov As String = EditWord.SaveFile("\\engineering4\quote\test.doc")
                If SaveDov <> "" Then
                    Lab_Error.Text = SaveDov
                End If
                ' Set flag to show processing was all OK
                PostDocument = True
            Else
                Lab_Error.Text = OpenDoc
            End If
        End Function
    End Class

    The only thing left to do is save the document under a different file name.

    just need to stream out to a new doc file, HOW?


    • Edited by Born59 Wednesday, April 25, 2012 6:52 AM
    Tuesday, April 24, 2012 3:25 PM
  • Hi a{ReAl}Sidewinder,

    Thanks for posting in the MSDN Forum.

    I feel this issue will have no trouble with Open Xml. However I'm wondering to understand your goal more clearly. Please clarify following options for further research:

    1. Where you will get the information for the document fields which you want replace? 
    2. Will your new document show in the webbroswer?

    I will show you sample code when you clarify it.

    Have a good day,

    Tom


    Tom Xu [MSFT]
    MSDN Community Support | Feedback to us

    Wednesday, April 25, 2012 2:53 AM
    Moderator
  • Hi Tom

    Thanks for replying.

    This is an Intranet site (Internal to the company only) I have build a bespoke website to track jobs through the company and what I am doing here is only a small part of the whole structure, it’s been running well for sometime now but to enhance it further I would like to control the creation of customer Quotes.

    So this programmatic solution will use a template document with all of our headers and footers setup including various images for standards.

    The web page enable the user to enter the customer name through a auto-complete dropdown box that is linked to the customer database of addresses, it will also ask them via a auto-complete text box the customers name and job description.

    It then takes this information and runs the Search-Replace function on the Template file filling in the information required.

    Last but not least I need to rename the document to the latest Quote number being something like 43523-H04-Customer_Name.doc and place this in a directory on another server.

    Then through back a link to the file so they can open it and fill in the rest of the Quote body with the Quote break down and pricing, this link will be in the form of file://server_name/Quote/43523-H04-Customer_Name.doc

    The other problem I have is the are a mixture of MS-Office products being 2003/2007 and 2010, it would be nice to save the document as a .doc and not a .docx but this is only a small problem as 2003 has the abilities to open docx via conversion.

    The source Template is a .docx or should be a .dotx file.

    Anymore information require please ask.


    A picture paints a thousand words, a Video has thousands of pictures All help files should be shown as videos.

    • Marked as answer by Born59 Thursday, April 26, 2012 9:37 AM
    • Unmarked as answer by Born59 Thursday, April 26, 2012 9:37 AM
    Wednesday, April 25, 2012 6:46 AM
  • Not the way I wanted to do it but it works just as well.

        Protected Function PostDocument(QuoteNumber As String, FileName As String) As Boolean
            PostDocument = False
            ' Get all Required Information
            Dim ShortCustomerName As String = Mid(Txb_Individual.Text.Trim, 1, InStr(Txb_Individual.Text, " ") - 1)
            Dim FormalCustomerName As String = Mid(Txb_Individual.Text.Trim, 1, 1).ToUpper & "." & Mid(Txb_Individual.Text.Trim, InStr(Txb_Individual.Text.Trim, " ") + 1, 1).ToUpper & Mid(Txb_Individual.Text.Trim, InStr(Txb_Individual.Text.Trim, " ") + 2).ToLower
            ' Get class up and runing
            Dim EditWord As New Openxml()
            ' Copy Template file
            Try
                File.Copy(MapPath("workingfiles/quotes.dotx"), MapPath("workingfiles/" & FileName))
            Catch ex As Exception
                Lab_Error.Text = "Oops unable to create Quote file:" & MapPath("workingfiles/" & FileName) & "<br>Error:" & ex.Message
                Exit Function
            End Try
            ' Open document
            Dim OpenDoc As String = EditWord.OpenFile(MapPath("workingfiles/" & FileName))
            If OpenDoc = "" Then
                Dim results As String = ""
                ' Do word replacment
                EditWord.ReplaceText("Company", Txb_Company.Text.Trim)
                Dim CustomerAddress() As String = Split(GetCustomerAddress(Txb_Company.Text.Trim), "|")
                For i As Integer = 1 To 5
                    If i - 1 <= UBound(CustomerAddress) Then
                        EditWord.ReplaceText("Ad" & i, CustomerAddress(i - 1).Trim)
                    Else
                        EditWord.ReplaceText("Ad" & i, "")
                    End If
                Next
                EditWord.ReplaceText("FAO", "Attn. " & FormalCustomerName)
                EditWord.ReplaceText("PeakQuote", QuoteNumber)
                EditWord.ReplaceText("Today", Now.Date.ToLongDateString)
                EditWord.ReplaceText("Name", ShortCustomerName)
                EditWord.ReplaceText("User", Replace(Request.Cookies("ITR")("FullUserName").ToString, "+", " "))
                ' Save the new Quote to were the user expects it to be.
                Dim SaveDov As String = EditWord.SaveFile("\\engineering4\quote\" & FileName)
                If SaveDov <> "" Then
                    Lab_Error.Text = SaveDov
                    Exit Function
                End If
                Try
                    File.Copy(MapPath("workingfiles/" & FileName), "\\engineering4\quote\" & FileName)
                    File.Delete(MapPath("workingfiles/" & FileName))
                    ' Set flag to show processing was all OK
                    PostDocument = True
                Catch ex As Exception
                    Lab_Error.Text = ex.Message
                End Try
            Else
                Lab_Error.Text = OpenDoc
            End If
        End Function

    One thing to note for anybody else, you can’t ‘Search and Replace’ well replace with a string containing vbCrLf as you are editing the xml direct and to get new lines you would have to create new sections for each line.

    I did it the simple way (cop-out) as you can see around the customer Address with Ad1,2,3,4,5

    Anyway all in and working now.

    Thanks all.


    A picture paints a thousand words, a Video has thousands of pictures All help files should be shown as videos.

    • Marked as answer by Born59 Thursday, April 26, 2012 9:39 AM
    Thursday, April 26, 2012 9:39 AM
  • Hi a{ReAl}Sidewinder,

    This just My work round I hope it can help you.

    Imports System.IO
    Imports DocumentFormat.OpenXml.Packaging
    Imports DocumentFormat.OpenXml.Wordprocessing
    
    Public Class _Default
        Inherits System.Web.UI.Page
    
        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    
        End Sub
    
        Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim CName As String
            Dim CAddress As String
            Dim CToday As String
            Dim IPath, OPath As String
            Dim MDP As MainDocumentPart
            Dim Doc As Document
            Dim NameRegex As Regex = New Regex("Name")
            Dim AddressRegex As Regex = New Regex("Address")
            Dim TodayRegex As Regex = New Regex("Today")
            Dim Paragraph As Paragraph
            Dim Paragraphs As List(Of Paragraph)
            'Dim Run As Run
            'Dim Runs As List(Of Run)
            Dim Text As Text
            Dim Texts As List(Of Text)
    
            CName = TextBox1.Text
            CAddress = TextBox2.Text
            CToday = TextBox3.Text
    
            IPath = "C:\*******\Template.docx"
            OPath = "\\******\" & CName & ".docx"
    
            Try
                File.Copy(IPath, OPath, True)
                Using WPD As WordprocessingDocument = WordprocessingDocument.Open(OPath, True)
                    MDP = WPD.MainDocumentPart
                    Doc = MDP.Document
                    Paragraphs = Doc.Descendants(Of Paragraph)().ToList()
    
                    For Each Paragraph In Paragraphs
                        Texts = Paragraph.Descendants(Of Text)().ToList()
                        For Each Text In Texts
                            Text.Text = NameRegex.Replace(Text.Text, CName)
                            Text.Text = AddressRegex.Replace(Text.Text, CAddress)
                            Text.Text = TodayRegex.Replace(Text.Text, CToday)
                        Next
                    Next
                End Using
            Catch ex As Exception
                Debug.Print(ex.Message)
            End Try
            TextBox1.Text = ""
            TextBox2.Text = ""
            TextBox3.Text = ""
        End Sub
    End Class

    By the way, Word 2003 document isn't formated by Open xml. So we can't use Open xml sdk to generate Word 2003 document.

    I hope it can help you,

    Have a good day,

    Tom


    Tom Xu [MSFT]
    MSDN Community Support | Feedback to us

    Thursday, April 26, 2012 10:08 AM
    Moderator