Save as text file in a certain format similar to an xml

PippaThePointer

New Member
Joined
Sep 21, 2023
Messages
31
Office Version
  1. 2016
Platform
  1. Windows
Hi,
Hoping for some simple advice as my brain is cooked today.
I have a data sheet that contains column A 'Size' and then Column B,C,D contain text.
I would like to run a vba to save the data as a text file, but i need it in a certain way.

The resulting text file ideally would be one file but the data grouped into <begindoc> <enddoc> from B,C,D and ideally also grouped by same data in Column A (Size). This one text file would then be saved to a certain location with .mergefile as the extention

SizeFirstSecondThird
Size1duplicate=2,FileA.pdfduplicate=0,FileA.pdfduplicate=2,FileA.pdf
Size1duplicate=0,FileB.pdfduplicate=0,FileB.pdfduplicate=1,FileB.pdf
Size2duplicate=2,FileC.pdfduplicate=2,FileC.pdfduplicate=2,FileC.pdf
Size2duplicate=2,FileD.pdfduplicate=2,FileD.pdfduplicate=2,FileD.pdf
Size2duplicate=2,FileE.pdfduplicate=2,FileE.pdfduplicate=2,FileE.pdf

inputfolder=C:\testfileinputlocation
outputfolder=C:\testfileoutputlocation
reportfile=C:\testlogfilelocation\ProcessingLog.htm
overwrite=no
padtoeven=no
author=Me
title=filename
// First output document is data from column N for each size in column C
<begindoc>
duplicate=2,FileA.pdf
duplicate=0,FileB.pdf

document=First-Size1.pdf
<enddoc>
// Second output document
<begindoc>
duplicate=0,FileA.pdf
duplicate=0,FileB.pdf

document=Second-Size1.pdf
<enddoc>
// Third output document
<begindoc>
duplicate=2,FileA.pdf
duplicate=1,FileB.pdf

document=Third-Size1.pdf
<enddoc>
// repeat again for next size....
 
this worked perfectly. Ive made lots of other small changes to test a few things and to learn how all the bits work.
for instance if i have more columns i change the range and also "For I = 1 To 3' to 1 to 4. But i cant work out which offset to change in the 'Create Formatted text' section if for example the data was in different columns such as C,D,E. The reason is if i wanted to not have the formula in the spreadsheet but instead in the VBA then the data would potentilally look like below. and i would want to use your VBA but include something along the lines of "duplicate" & WS.Range("C2") & "," & WS.Range("B2")
SizeFileheading1heading2Heading3
A4FileA.pdf
2​
4​
6​
A4FileB.pdf
3​
5​
7​
Hi again,
This has been so helpfull but i am struggling a bit to understand how the the code works for the three kinds (B,C,D) and how to edit or unpick the range. Any chance you could give me an example without the repeat across the columns so it worked for just one column category? The data i get before someone messes with it is usually one worksheet per store anyway.
lets say the data came in like the following. Could you redo you original VBA example so it gave me the same thing and grouped by column A but only looked at range A2:B?
GroupQTY
A4-StoreAduplicate=2,FileA.pdf
A4-StoreAduplicate=2,FileB.pdf
A4-StoreBduplicate=2,FileA.pdf
A4-StoreBduplicate=2,FileB.pdf
 
Upvote 0

Excel Facts

When did Power Query debut in Excel?
Although it was an add-in in Excel 2010 & Excel 2013, Power Query became a part of Excel in 2016, in Data, Get & Transform Data.
One possibility
VBA Code:
Sub MakeFile()
    Dim WB As Workbook
    Dim WS As Worksheet, WSD As Worksheet
    Dim rng As Range, R As Range, rng2 As Range
    Dim I As Long, LastRow As Long, DestRow As Long, DestColumn As Long
    Dim VA As Variant
    Dim DocName As String, LastSize As String, OutFile As String
    Dim inputfolder As String, outputfolder As String, reportfile As String, overwrite As String, padtoeven As String, author As String, title As String
   
    '===============User data ========================
    inputfolder = "C:\testfileinputlocation"
    'outputfolder = "C:\testfileoutputlocation"
    outputfolder = "C:\Users\223103252\Documents\TestFiles\"
    reportfile = "C:\testlogfilelocation\ProcessingLog.htm"
    overwrite = "no"
    padtoeven = "no"
    author = "Me"
    title = "filename"
   
    'Output File
    OutFile = outputfolder & "TestFile.Merge"
    '=================================================
    Application.ScreenUpdating = False
    Set WB = ActiveWorkbook
    Set WS = ActiveSheet
       
    'Add temporary worksheet and copy data to it.
    On Error Resume Next
    Application.DisplayAlerts = False
    ThisWorkbook.Worksheets("$TempSheet").Delete
    Application.DisplayAlerts = True
    On Error GoTo 0
   
    Set WSD = ThisWorkbook.Worksheets.Add
    WSD.Name = "$TempSheet"
   
    With WS
        Set rng2 = .Range("A2:D" & .Range("A" & .Rows.Count).End(xlUp).Row)
    End With
    rng2.Copy WSD.Range("A1") 'copy data to temporary worksheet
   
    'create formatted text
    With WSD
        Set rng = .Range("A1", .Range("A" & .Rows.Count).End(xlUp))
        For Each R In rng
            For I = 1 To 3
                R.Offset(0, I).Value = R.Offset(0, I).Value & "$" & I
            Next I
        Next R
       
        For I = 2 To 3
            LastRow = .Range("B" & .Rows.Count).End(xlUp).Row
            rng.Offset(, I).Resize(, 1).Cut .Cells(LastRow + 1, 2)
            rng.Copy .Cells(LastRow + 1, 1)
        Next I
       
        'Sort
        .UsedRange.Sort Key1:=.Range("A1"), Order1:=xlAscending, Header:=xlYes
       
        Set rng = .Range("A1", .Range("A" & .Rows.Count).End(xlUp))
       
        DestRow = 1
        DestColumn = 5
       
        'Write header information
        WriteLine WSD, "inputfolder  = " & inputfolder, DestRow, DestColumn
        WriteLine WSD, "outputfolder  = " & outputfolder, DestRow, DestColumn
        WriteLine WSD, "reportfile  = " & reportfile, DestRow, DestColumn
        WriteLine WSD, "overwrite  = " & overwrite, DestRow, DestColumn
        WriteLine WSD, "padtoeven  = " & padtoeven, DestRow, DestColumn
        WriteLine WSD, "author  = " & author, DestRow, DestColumn
        WriteLine WSD, "title  = " & title, DestRow, DestColumn
       
        'Build formatted text
        LastSize = ""
        For Each R In rng
            R.Value = R.Value & "$" & Right(R.Offset(, 1).Value, 1)
            With R.Offset(, 1)
                VA = Split(.Value, "$")
                .Value = VA(0)
            End With
            If LastSize = "" Then
                WriteLine WSD, "<begindoc>", DestRow, DestColumn
            ElseIf R.Value <> LastSize Then
                WriteLine WSD, DocName, DestRow, DestColumn
                WriteLine WSD, "<enddoc>", DestRow, DestColumn
                WriteLine WSD, "<begindoc>", DestRow, DestColumn
            End If
            WriteLine WSD, R.Offset(, 1).Value, DestRow, DestColumn
            VA = Split(R.Value, "$")
            Select Case VA(1)
                Case 1
                    DocName = "document=" & "First-" & VA(0) & ".pdf"
                Case 2
                    DocName = "document=" & "Second-" & VA(0) & ".pdf"
                Case 3
                    DocName = "document=" & "Third-" & VA(0) & ".pdf"
            End Select
            LastSize = R.Value
        Next R
       
        WriteLine WSD, DocName, DestRow, DestColumn
        WriteLine WSD, "<enddoc>", DestRow, DestColumn
       
        'Write to text file.
        Set rng = .Range(.Cells(1, DestColumn), .Cells(.Rows.Count, DestColumn).End(xlUp))
        Open OutFile For Output Access Write As #1     ' Open text file for write
        For Each R In rng
            Print #1, R.Value                          ' Write to output file
        Next R
        Close #1                                       ' Close file.
        .Columns.AutoFit
    End With
   
    'Clean up
    On Error Resume Next
    Application.DisplayAlerts = False
    WSD.Delete
    Application.DisplayAlerts = True
    On Error GoTo 0
    Application.ScreenUpdating = True
   
    MsgBox "New file created:" & vbCr & vbCr & OutFile, vbOKOnly Or vbInformation, Application.Name
End Sub
Hi again,
This has been so helpfull but i am struggling a bit to understand how the the code works for the three kinds (B,C,D) and how to edit or unpick the range. Any chance you could give me an example without the repeat across the columns so it worked for just one column category? The data i get before someone messes with it is usually one worksheet per store anyway.
lets say the data came in like the following. Could you redo you original VBA example so it gave me the same thing and grouped by column A but only looked at range A2:B?
GroupQTY
A4-StoreAduplicate=2,FileA.pdf
A4-StoreAduplicate=2,FileB.pdf
A4-StoreBduplicate=2,FileA.pdf
A4-StoreBduplicate=2,FileB.pdf
 
Upvote 0
You are changing the requirements so much I'm not clear on what you are trying to do. Perhaps you could use the XL2BB add-in to post some better data?

 
Upvote 0
You are changing the requirements so much I'm not clear on what you are trying to do. Perhaps you could use the XL2BB add-in to post some better data?

Sorry, I guess i'm trying to learn what you wrote so i can adapt it for different needs and i keep getting diffenent data from my source.
Good timing though, as now i realise that this example does not work if there is a formula in there. I was just tyring to work out how and where to amend that in the code. I think its in the 'add temp worksheet and copy and copy there' bit and needs some sort of "range.value' added in.

I will get a mini sheet up to you shortly. I have made up a new sheet that has more info on it but kept the 4 important columns i wanted at the end as i think i would eventually work out how to copy s2:V and go from there. But not with the formaula in it....
 

Attachments

  • Screenshot 2024-03-07 172513.png
    Screenshot 2024-03-07 172513.png
    28.6 KB · Views: 5
Upvote 0
You are changing the requirements so much I'm not clear on what you are trying to do. Perhaps you could use the XL2BB add-in to post some better data?

I hope i have done this right. This is the demo spreadsheet i have created. The person who currently does this task, she has to manually paste in store a, b, c from individual spreadsheets, but the data she needs is only certain rows of that data, ie 31-100. I have some other macro that can promt to get file and pull data but im not sure yet that the supplied content is reliable so for now i left alone (mabey next topic). So once the data is copied here i want to then take those formula cells and run them into the txt file. Im still running through my head the best way within my expertise to solve this, but i thought if i had multipe macro and buttons i could for instance have macro for 'one store (a only)', two store (a and b), or three store (abc). Once i have the text file i can run that via either of two app servers i manage that either run xml, csv or text that will combine 1000s of pdf files, impose them and then run to schedule on a some impressive digital print hardware in colated sets. This xcell bit im trying to improve because there is so much manual input going on.


Template - Copy.xlsm
ABCDEFGHIJKLMNOPQRSTUV
1(Will add macro button here….)Store AStore BStore CTOTALSScript Data
2Image ReferenceDescriptionFilenameSIZE12 KINDSStore A 12 PagesStore A 2 SetsStore B 60 PagesStore B 11 SetsStore C 32 PagesStore C 8 SetsTOTALS 80 Pages 18 SetsSizeStore A copiesStore B CopiesStore C Copies
3File AFileA.pdf105x2974412873286416 105x297duplicate=1,FileA.pdfduplicate=7,FileA.pdfduplicate=8,FileA.pdf
4File BFileB.pdf105x29788132400162105x297duplicate=1,FileB.pdfduplicate=4,FileB.pdf 
51212260113288018
Sheet1
Cell Formulas
RangeFormula
E2E2=CONCATENATE(E5," KINDS")
H2,N2,K2H2=CONCATENATE(G1," ",H5," Sets")
Q2Q2=CONCATENATE(Q1," ",Q5," Sets")
Q3Q3=SUM(H3+K3+N3)
S3:S4S3=D3
T3:T4T3=IF(H3>0,CONCATENATE("duplicate=",H3,",",$C3),"")
U3:U4U3=IF(K3>0,CONCATENATE("duplicate=",K3,",",$C3),"")
V3:V4V3=IF(N3>0,CONCATENATE("duplicate=",N3,",",$C3),"")
G2,P2,M2,J2G2=CONCATENATE(G1," ",G5," Pages")
M3:M4,J3:J4,G3:G4G3=($E3*H3)
P3:P4P3=SUM(E3*Q3)
E5,P5:Q5,M5:N5,J5:K5,G5:H5E5=SUBTOTAL(109,E3:E4)
 
Last edited:
Upvote 0
Book3
ABCD
1SizeFirstSecondThird
2Size1duplicate=2,FileA.pdfduplicate=0,FileA.pdfduplicate=2,FileA.pdf
3Size1duplicate=0,FileB.pdfduplicate=0,FileB.pdfduplicate=1,FileB.pdf
4Size2duplicate=2,FileC.pdfduplicate=2,FileC.pdfduplicate=2,FileC.pdf
5Size2duplicate=2,FileD.pdfduplicate=2,FileD.pdfduplicate=2,FileD.pdf
6Size2duplicate=2,FileE.pdfduplicate=2,FileE.pdfduplicate=2,FileE.pdf
Sheet1

The post showing the larger spreadsheet structure is more information than I need. There is probably a lot of work you could do to better gather the data from each store an put it somewhere to better generate the text file, but that's waaaay beyond the scope of this problem and those other problems should be the subject of other threads.

The original set of data looked like the above and the task was to create a single ordered and sorted list from the three columns of data and the write that to a faux XML format text file. So the only thing I need to know is which columns match up to those and contain the data that is to be written to the text file. Say for example, this:
Cell Formulas
RangeFormula
S3:S4S3=D3
T3:T4T3=IF(H3>0,CONCATENATE("duplicate=",H3,",",$C3),"")
U3:U4U3=IF(K3>0,CONCATENATE("duplicate=",K3,",",$C3),"")
V3:V4V3=IF(N3>0,CONCATENATE("duplicate=",N3,",",$C3),"")


The code would be something like this. It does not matter if the cells contain formulas.
VBA Code:
Sub MakeFile()
    Dim WB As Workbook
    Dim WS As Worksheet, WSD As Worksheet
    Dim rng As Range, R As Range, rng2 As Range
    Dim FirstDataCol As String, LastDataCol As String
    Dim FirstDataRow As Long
    Dim I As Long, LastRow As Long, DestRow As Long, DestColumn As Long
    Dim VA As Variant
    Dim DocName As String, LastSize As String, OutFile As String
    Dim inputfolder As String, outputfolder As String, reportfile As String, overwrite As String, padtoeven As String, author As String, title As String

    Sheets("Sheet2").Activate

    '===============User data ========================
    inputfolder = "C:\testfileinputlocation"
    outputfolder = "C:\testfileoutputlocation"
    reportfile = "C:\testlogfilelocation\ProcessingLog.htm"
    overwrite = "no"
    padtoeven = "no"
    author = "Me"
    title = "filename"

    'Output File
    OutFile = outputfolder & "TestFile.Merge"
    '=================================================
    Application.ScreenUpdating = False
    Set WB = ActiveWorkbook
    Set WS = ActiveSheet

    'Add temporary worksheet and copy data to it.
    On Error Resume Next
    Application.DisplayAlerts = False
    ThisWorkbook.Worksheets("$TempSheet").Delete
    Application.DisplayAlerts = True
    On Error GoTo 0

    Set WSD = ThisWorkbook.Worksheets.Add
    WSD.Name = "$TempSheet"

    'Define the columns containing the relevant data here.
    FirstDataCol = "S"
    LastDataCol = "V"
    FirstDataRow = 3

    With WS
        Set rng2 = .Range(FirstDataCol & FirstDataRow & ":" & LastDataCol & .Range(FirstDataCol & .Rows.Count).End(xlUp).Row)
    End With

    rng2.Copy
    WSD.Range("A2").PasteSpecial (xlPasteValues)      'copy data to temporary worksheet
    WSD.Columns.AutoFit

    'create formatted text
    With WSD
        Set rng = .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
        rng.Range("A1").Offset(-1, 0).Value = 0
        For Each R In rng
            For I = 1 To rng2.Columns.Count - 1
                rng.Range("A1").Offset(-1, I).Value = I
                If Trim(R.Offset(0, I).Value) = "" Then
                    R.Offset(0, I).Value = "Delete"
                Else
                    R.Offset(0, I).Value = R.Offset(0, I).Value & "$" & I
                End If
            Next I
        Next R

        For I = 2 To rng2.Columns.Count - 1
            LastRow = .Range("B" & .Rows.Count).End(xlUp).Row
            rng.Offset(, I).Resize(, 1).Cut .Cells(LastRow + 1, 2)
            rng.Copy .Cells(LastRow + 1, 1)
        Next I

        'Sort
        .UsedRange.Sort Key1:=.Range("A1"), Order1:=xlAscending, Header:=xlYes

        Set rng = .Range("A1", .Range("A" & .Rows.Count).End(xlUp))

        'Delete empty cells
        With rng.Resize(, 2)
            .AutoFilter Field:=2, Criteria1:="=Delete"
            If Not .SpecialCells(xlCellTypeVisible) Is Nothing Then
                .SpecialCells(xlCellTypeVisible).EntireRow.Delete
            End If
        End With
        .AutoFilterMode = False

        DestRow = 1
        DestColumn = 10

        'Write header information
        WriteLine WSD, "inputfolder  = " & inputfolder, DestRow, DestColumn
        WriteLine WSD, "outputfolder  = " & outputfolder, DestRow, DestColumn
        WriteLine WSD, "reportfile  = " & reportfile, DestRow, DestColumn
        WriteLine WSD, "overwrite  = " & overwrite, DestRow, DestColumn
        WriteLine WSD, "padtoeven  = " & padtoeven, DestRow, DestColumn
        WriteLine WSD, "author  = " & author, DestRow, DestColumn
        WriteLine WSD, "title  = " & title, DestRow, DestColumn

        'Build formatted text
        LastSize = ""
        For Each R In rng
            R.Value = R.Value & "$" & Right(R.Offset(, 1).Value, 1)
            With R.Offset(, 1)
                VA = Split(.Value, "$")
                .Value = VA(0)
            End With
            If LastSize = "" Then
                WriteLine WSD, "<begindoc>", DestRow, DestColumn
            ElseIf R.Value <> LastSize Then
                WriteLine WSD, DocName, DestRow, DestColumn
                WriteLine WSD, "<enddoc>", DestRow, DestColumn
                WriteLine WSD, "<begindoc>", DestRow, DestColumn
            End If
            WriteLine WSD, R.Offset(, 1).Value, DestRow, DestColumn
            VA = Split(R.Value, "$")
            Select Case VA(1)
            Case 1
                DocName = "document=" & "First-" & VA(0) & ".pdf"
            Case 2
                DocName = "document=" & "Second-" & VA(0) & ".pdf"
            Case 3
                DocName = "document=" & "Third-" & VA(0) & ".pdf"
            End Select
            LastSize = R.Value
        Next R

        WriteLine WSD, DocName, DestRow, DestColumn
        WriteLine WSD, "<enddoc>", DestRow, DestColumn

        'Write to text file.
        Set rng = .Range(.Cells(1, DestColumn), .Cells(.Rows.Count, DestColumn).End(xlUp))
        Open OutFile For Output Access Write As #1    ' Open text file for write
        For Each R In rng
            Print #1, R.Value                         ' Write to output file
        Next R
        Close #1                                      ' Close file.
        .Columns.AutoFit
    End With

    'Clean up
    On Error Resume Next
    Application.DisplayAlerts = False
    WSD.Delete
    Application.DisplayAlerts = True
    On Error GoTo 0
    Application.ScreenUpdating = True

    MsgBox "New file created:" & vbCr & vbCr & OutFile, vbOKOnly Or vbInformation, Application.Name
End Sub

Private Sub WriteLine(DestWS As Worksheet, WriteStr As String, ByRef DestRow As Long, ByRef DestColumn As Long)
    DestWS.Cells(DestRow, DestColumn).Value = WriteStr
    DestRow = DestRow + 1
End Sub
 
Upvote 0
Solution
The best way to understand the function is to comment out the line below and then use the debugger to single step though the code while watching the temporary sheet.

VBA Code:
  'Clean up
    On Error Resume Next
    Application.DisplayAlerts = False
    'WSD.Delete                                                                <-- temporarily comment out. 
    Application.DisplayAlerts = True
    On Error GoTo 0
    Application.ScreenUpdating = True
 
Upvote 0
The best way to understand the function is to comment out the line below and then use the debugger to single step though the code while watching the temporary sheet.

VBA Code:
  'Clean up
    On Error Resume Next
    Application.DisplayAlerts = False
    'WSD.Delete                                                                <-- temporarily comment out.
    Application.DisplayAlerts = True
    On Error GoTo 0
    Application.ScreenUpdating = True
Hi Riv,
I posted a new question based on this fantastic code you helped me with.
You might have a quicker answer for me.
 
Upvote 0

Forum statistics

Threads
1,223,896
Messages
6,175,264
Members
452,627
Latest member
KitkatToby

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top