1<?xml version="1.0" encoding="UTF-8"?> 2<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd"> 3<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Validate" script:language="StarBasic"> 4'############################################ 5' VALIDATION ROUTINES 6' 7' May, 19 2004 - fpe 8'############################################ 9 10Dim sSwitchType As String 11Dim sCellSwitchType As String 12Dim sCaseType As String 13Dim sCellCaseType As String 14Dim sDefaultType As String 15Dim sCellDefaultType As String 16Dim bDefaultSet As Boolean 17Dim bCellDefaultSet As Boolean 18Dim bCaseSet As Boolean 19Dim bCellCaseSet As Boolean 20Dim aTagsOpen(0) As String 21Dim aCellTagsOpen(0) As String 22Dim bWarn As Boolean 23Dim bWarnEmptyPara As Boolean 24Dim bWarnParaNoID As Boolean 25 26 27Sub ValidateXHP 28 Validate 29End Sub 30 31Sub Validate 32 33 If not IsHelpFile Then 34 msgbox(strErr_NoHelpFile) 35 Exit Sub 36 End If 37 38 oDoc = StarDesktop.CurrentComponent 39 sSwitchType = "" 40 sCaseType = "" 41 sDefaultType = "" 42 bWarn = TRUE 43 bWarnEmptyPara = TRUE 44 bWarnParaNoID = TRUE 45 46 CheckMetaData(oDoc) 47 CheckHeading(oDoc) 48 49 Enum = oDoc.Text.createEnumeration 50 Do While Enum.hasMoreElements 51 52 TextElement = Enum.nextElement 53 If TextElement.supportsService("com.sun.star.text.Paragraph") Then ' we are a paragraph 54 55 CheckSwitches(TextElement) 56 CheckParaID(TextElement) 57 CheckParaFormat(TextElement) 58 CheckTags(TextElement) 59 CheckInlineTags(TextElement) 60 61 ElseIf TextElement.supportsService("com.sun.star.text.TextTable") Then 62 63 If sSwitchType <> "" AND (sCaseType = "" AND sDefaultType = "") Then '<------ 64 Terminate("Switch must be closed or case/default must be opened before a table starts.",tmpCellElement) 65 End If 66 67 CheckCell(TextElement) 68 End If 69 Loop 70 71 If sCaseType <> "" Then 72 Terminate("Previous case ("+sCaseType+") not closed!",TextElement) 73 End If 74 75 If sDefaultType <> "" Then 76 Terminate("Previous default not closed!",TextElement) 77 End If 78 79 If sSwitchType <> "" Then 80 Terminate("Previous switch ("+sSwitchType+") not closed!",TextElement) 81 End If 82 83 If ubound(aTagsOpen()) > 0 Then 84 Terminate("Element "+aTagsOpen(ubound(aTagsOpen()))+" not closed",TextElement) 85 End If 86 87 msgbox("Validation finished.") 88 89End Sub 90 91'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 92' CHECKCELL 93' checks a table cell contents 94'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 95 96Sub CheckCell(TE As Object) 97 On Local Error Goto ERRHANDLE: 98 99 CellName = "A1" 100 Cell = TE.getCellByName(CellName) 101 tmpCellEnum = Cell.createEnumeration 102 tmpCellElement = tmpCellEnum.nextElement 103 104 Rows = TE.getRows 105 Cols = TE.getColumns 106 107 ReDim aCellTagsOpen(0) 108 109 For RowIndex = 1 to Rows.getCount() 110 111 For ColIndex = 1 to Cols.getCount() 112 113 CellName = Chr(64 + ColIndex) & RowIndex 114 Cell = TE.getCellByName(CellName) 115 CellEnum = Cell.createEnumeration 116 117 Do While CellEnum.hasMoreElements 118 119 CellElement = CellEnum.nextElement ' <-- MODIFY, check closed switches within cells 120 121 If CellElement.supportsService("com.sun.star.text.Paragraph") Then 122 CheckSwitchesInCell(CellElement) 123 CheckParaID(CellElement) 124 CheckParaFormat(CellElement) 125 CheckTagsInCell(CellElement) 126 CheckInlineTags(CellElement) 127 EndIf 128 129 Loop 130 131 If sCellCaseType <> "" Then 132 Terminate("Previous case ("+sCellCaseType+") not closed!",CellElement) 133 End If 134 135 If sCellSwitchType <> "" Then 136 Terminate("Previous switch ("+sCellSwitchType+") not closed!",CellElement) 137 End If 138 139 If ubound(aCellTagsOpen()) > 0 Then 140 Terminate("Element "+aCellTagsOpen(ubound(aCellTagsOpen()))+" not closed",CellElement) 141 End If 142 143 Next 144 Next 145 146 ERRHANDLE: 147 If Err <> 0 Then 148 msgbox "Error: "+chr(13)+ Error$,48,"D'oh!" 149 End If 150End Sub 151 152'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 153' CHECK PARA ID 154' checks a paragraph for an ID 155'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 156 157Sub CheckParaID(TE As Object) 158 159 If Left(TE.ParaStyleName,4) = "hlp_" AND Not(Left(TE.ParaStyleName,8) = "hlp_aux_") Then 160 161 sText = TE.GetString 162 163 If sText = "" Then 164 If bWarnEmptyPara Then 165 Warn("Empty Paragraph","Empty paragraphs should be avoided. Do not use empty paragraphs for formatting purpose.",TE) 166 bWarnEmptyPara = FALSE 167 End If 168 Else 169 170 TP = TE.createEnumeration 171 Ct = 0 172 posID = 0 173 174 While TP.hasmoreElements 175 Ct = Ct+1 176 TPE = TP.nextElement 177 If TPE.TextPortionType="TextField" Then 178 If TPE.TextField.TextFieldMaster.Name="ID" Then 179 posID = Ct 180 End If 181 End If 182 ' Lets cheat and allow empty strings before the ID -- otherwise we'll get 183 ' a validation error if a paragraph starts at the top of a page after 184 ' a page break (for whatever reason) 185 If TPE.String = "" Then 186 Ct = Ct-1 187 End If 188 Wend 189 190 If posID = 0 Then 191 If bWarnParaNoID Then 192 Warn("Paragraph has no id.","IDs will be assigned on safe. You can also assign an ID using the Assign Paragraph ID menu item",TPE) 193 bWarnParaNoID = FALSE 194 InsertNewParaData 195 Else 196 oCur = TE.getText.createTextCursorByRange(TE) 197 thiscomponent.getcurrentcontroller.select(oCur) 198 InsertNewParaData 199 End If 200 ElseIf posID > 1 Then 201 Terminate("Paragraph ID not at the start of the paragraph. The paragraph ID must be the first element of a paragraph. Move the ID to the beginning of the paragraph",TPE) 202 End If 203 204 End If 205 206 End If 207End Sub 208 209'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 210' CHECK PARA FORMAT 211'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 212Sub CheckParaFormat(TE As Object) 213 214 sText = TE.GetString 215 If Left(TE.ParaStyleName,4) <> "hlp_" AND sText <> "" Then ' just disregard empty paras in wrong formats 216 Warn("Invalid paragraph format. Contents will be lost.",_ 217 "Use only the paragraph styles starting with ""hlp_""."+_ 218 " Paragraphs in other formats will be lost on export",TE) 219 End If 220 221End Sub 222 223'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 224' CHECK SWITCHES 225'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 226Sub CheckSwitches(TE As Object) 227 228 If TE.ParaStyleName="hlp_aux_switch" Then ' we are a switch or case or default 229 sText = TE.GetString ' get the switch contents 230 231 If Left(sText,8) = "<SWITCH " Then ' an opening switch tag 232 233 If sSwitchType = "" Then ' no other switch is open 234 sSwitchType = Right(sText,Len(sText)-16) 235 sSwitchType = Left(sSwitchType,InStr(sSwitchType,"""")-1) 236 237 If (sSwitchType <> "sys" AND sSwitchType <> "appl" AND sSwitchType <> "distrib") Then 238 Terminate("Unknown switch type """+sSwitchType+"""",TE) 239 End If 240 241 Else 242 Terminate("Previous switch ("+sSwitchType+") not closed!",TE) 243 End If 244 245 End If ' OPENING SWITCH 246 247 If Left(sText,8) = "</SWITCH" Then ' a closing switch tag 248 249 If sSwitchType = "" Then ' there was no switch open 250 Terminate("No switch open!",TE) 251 Else 252 If not(bCaseSet OR bDefaultSet) Then 253 Terminate("Empty switch",TE) 254 End If 255 256 If sCaseType <> "" Then ' there is still a case open 257 Terminate("Previous case ("+sCaseType+") not closed!",TE) 258 End If 259 sSwitchType = "" 260 bDefaultSet = FALSE 261 bCaseSet = FALSE 262 End If 263 264 End If ' CLOSING SWITCH 265 266 If Left(sText,6) = "<CASE " Then ' an opening case tag 267 268 If bDefaultSet Then 269 Terminate("No case after default allowed.",TE) 270 End If 271 272 If sCaseType = "" Then 273 sCaseType = Right(sText,Len(sText)-14) 274 sCaseType = Left(sCaseType,InStr(sCaseType,"""")-1) 275 bCaseSet = TRUE 276 If sSwitchType = "" Then 277 Terminate("Case without switch",TE) 278 End If 279 Else 280 Terminate("Previous case ("+sCaseType+") not closed!",TE) 281 End If 282 283 End If ' OPENING CASE 284 285 If Left(sText,6) = "</CASE" Then ' a closing case tag 286 287 If sCaseType = "" Then 288 Terminate("No case open!",TE) 289 Else 290 sCaseType = "" 291 End If 292 293 End If ' CLOSING CASE 294 295 If Left(sText,8) = "<DEFAULT" Then ' an opening default tag 296 297 If sCaseType = "" Then 298 If (sDefaultType <> "" OR bDefaultSet) Then 299 Terminate("Multiple default not allowed.",TE) 300 Else 301 sDefaultType = "DEFAULT" 302 303 If sSwitchType = "" Then 304 Terminate("Default without switch",TE) 305 End If 306 End If 307 sDefaultType = "DEFAULT" 308 bDefaultSet = TRUE 309 Else 310 Terminate("Previous case ("+sCaseType+") not closed!",TE) 311 End If 312 313 End If ' OPENING CASE 314 315 If Left(sText,9) = "</DEFAULT" Then ' a closing default tag 316 317 If sDefaultType <> "DEFAULT" Then 318 Terminate("No default open!",TE) 319 Else 320 sDefaultType = "" 321 End If 322 323 End If ' CLOSING CASE 324 Else ' We are not hlp_aux_switch 325 If (sSwitchType <> "" AND sCaseType = "" AND sDefaultType = "") Then 326 Terminate("Nothing allowed between switch and case or default or /case or /default and /switch", TE) 327 End If 328 End If 329 330End Sub 331 332'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 333' CHECK SWITCHES IN A CELL 334'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 335Sub CheckSwitchesInCell(CE As Object) 336 337 If CE.ParaStyleName="hlp_aux_switch" Then ' we are a switch or case or default 338 sText = CE.GetString ' get the switch contents 339 340 If Left(sText,8) = "<SWITCH " Then ' an opening switch tag 341 342 If sCellSwitchType = "" Then ' no other switch is open 343 sCellSwitchType = Right(sText,Len(sText)-16) 344 sCellSwitchType = Left(sCellSwitchType,InStr(sCellSwitchType,"""")-1) 345 346 If (sCellSwitchType <> "sys" AND sCellSwitchType <> "appl" AND sCellSwitchType <> "distrib") Then 347 Terminate("Unknown switch type """+sCellSwitchType+"""",CE) 348 End If 349 350 Else 351 Terminate("Previous switch ("+sCellSwitchType+") not closed!",CE) 352 End If 353 354 End If ' OPENING SWITCH 355 356 If Left(sText,8) = "</SWITCH" Then ' a closing switch tag 357 358 If sCellSwitchType = "" Then ' there was no switch open 359 Terminate("No switch open!",CE) 360 Else 361 If not(bCellCaseSet OR bCellDefaultSet) Then 362 Terminate("Empty switch",CE) 363 End If 364 365 If sCellCaseType <> "" Then ' there is still a case open 366 Terminate("Previous case ("+sCellCaseType+") not closed!",CE) 367 End If 368 sCellSwitchType = "" 369 bCellDefaultSet = FALSE 370 bCellCaseSet = FALSE 371 End If 372 373 End If ' CLOSING SWITCH 374 375 If Left(sText,6) = "<CASE " Then ' an opening case tag 376 377 If bCellDefaultSet Then 378 Terminate("No case after default allowed.",CE) 379 End If 380 381 If sCellCaseType = "" Then 382 sCellCaseType = Right(sText,Len(sText)-14) 383 sCellCaseType = Left(sCellCaseType,InStr(sCellCaseType,"""")-1) 384 bCellCaseSet = TRUE 385 If sCellSwitchType = "" Then 386 Terminate("Case without switch",CE) 387 End If 388 Else 389 Terminate("Previous case ("+sCellCaseType+") not closed!",CE) 390 End If 391 392 End If ' OPENING CASE 393 394 If Left(sText,6) = "</CASE" Then ' a closing case tag 395 396 If sCellCaseType = "" Then 397 Terminate("No case open!",CE) 398 Else 399 sCellCaseType = "" 400 End If 401 402 End If ' CLOSING CASE 403 404 If Left(sText,8) = "<DEFAULT" Then ' an opening default tag 405 406 If sCellCaseType = "" Then 407 If (sCellDefaultType <> "" OR bCellDefaultSet) Then 408 Terminate("Multiple default not allowed.",CE) 409 Else 410 sCellDefaultType = "DEFAULT" 411 412 If sCellSwitchType = "" Then 413 Terminate("Default without switch",CE) 414 End If 415 End If 416 sCellDefaultType = "DEFAULT" 417 bCellDefaultSet = TRUE 418 Else 419 Terminate("Previous case ("+sCellCaseType+") not closed!",CE) 420 End If 421 422 End If ' OPENING CASE 423 424 If Left(sText,9) = "</DEFAULT" Then ' a closing default tag 425 426 If sCellDefaultType <> "DEFAULT" Then 427 Terminate("No default open!",CE) 428 Else 429 sCellDefaultType = "" 430 End If 431 432 End If ' CLOSING CASE 433 Else ' We are not hlp_aux_switch 434 If (sCellSwitchType <> "" AND sCellCaseType = "" AND sCellDefaultType = "") Then 435 Terminate("Nothing allowed between switch and case or default or /case or /default and /switch", CE) 436 End If 437 End If 438 439 440End Sub 441 442 443'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 444' TERMINATE VALIDATION WITH AN ERROR MESSAGE 445'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 446Sub Terminate(sStr As String, TE As Object) 447 448 oCur = TE.getText.createTextCursorByRange(TE) 449 thiscomponent.getcurrentcontroller.select(oCur) 450 msgbox sStr,48,"D'oh!" 451 Stop 452 453End Sub 454 455'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 456' SHOW A WARNING 457'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 458Sub Warn(sWarn As String, sSolv As String, Optional TE As Object) 459 460 If bWarn Then 461 BasicLibraries.LoadLibrary("HelpAuthoring") 462 oDialog = LoadDialog("HelpAuthoring", "dlgWarn") 463 oTxtWarn = oDialog.GetControl("txtWarning") 464 oTxtWarn.Text = sWarn 465 oTxtSolv = oDialog.GetControl("txtSolution") 466 oTxtSolv.Text = sSolv 467 468 If not(IsMissing(TE)) Then 469 oCur = TE.getText.createTextCursorByRange(TE) 470 thiscomponent.getcurrentcontroller.select(oCur) 471 End If 472 473 If oDialog.Execute() = 1 Then 474 oCbWarn = oDialog.GetControl("cbWarn") 475 If oCbWarn.State = 1 Then 476 bWarn = FALSE 477 End If 478 Exit Sub 479 Else 480 Stop 481 End If 482 End If 483End Sub 484 485'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 486' CHECK DOCUMENT META DATA 487'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 488Sub CheckMetaData(oDoc As Object) 489 490 sTopicID = oDoc.DocumentInfo.GetUserFieldValue(1) 491 492 If sTopicID <> AlphaNum(sTopicID) OR sTopicID="" Then 493 sTopicID = "topic_"+CreateID ' create a topic id 494 End If 495 496 oDoc.DocumentInfo.SetUserFieldValue(1,sTopicID) 497 sCreated = oDoc.DocumentInfo.GetUserFieldValue(2) 498 sEdited = oDoc.DocumentInfo.GetUserFieldValue(3) 499 sTitle = oDoc.DocumentInfo.Title 500 501 If sTitle="" OR sTitle="<Set Topic Title>" Then 502 Enum = document.Text.createEnumeration 503 Do While Enum.hasMoreElements 504 TextElement = Enum.nextElement 505 If TextElement.supportsService("com.sun.star.text.Paragraph") Then 506 If Left(TextElement.ParaStyleName,8)="hlp_head" Then 507 Enum2 = TextElement.createEnumeration 508 While Enum2.hasMoreElements 509 TextPortion = Enum2.nextElement 510 If Not(TextPortion.TextPortionType="TextField") Then 511 strg = strg + TextPortion.String 512 End If 513 Wend 514 document.DocumentInfo.Title = strg 515 Exit Do 516 End If 517 End If 518 Loop 519 End If 520 521 sIndex = oDoc.DocumentInfo.GetUserFieldValue(0) 522 523End Sub 524 525'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 526' CHECK IF HEADING EXISTS 527'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 528Sub CheckHeading(oDoc As Object) 529 530End Sub 531 532'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 533' CHECK FOR CORRECT INLINE TAGS 534'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 535Sub CheckInlineTags(TE As Object) 536 537 538 539 If Left(TE.ParaStyleName,4)="hlp_" AND (Left(TE.ParaStyleName,8)<>"hlp_aux_" OR TE.ParaStyleName="hlp_aux_bookmark") Then 540 541 Dim aTokens(0) As Object 542 Dim aInlineTagsOpen(0) As String 543 TP = TE.createEnumeration 544 545 While TP.hasmoreElements 546 sDim = ubound(aTokens())+1 547 ReDim Preserve aTokens(sDim) As Object 548 aTokens(sDim) = TP.nextElement 549 Wend 550 551 For i=1 to ubound(aTokens()) 552 Token = aTokens(i) 553 554 If Token.supportsService("com.sun.star.text.TextField") Then 555 sTag = Token.TextField.TextFieldMaster.Name 556 557 If Right(sTag,1)="_" Then ' a tag starts 558 559 sTagName = Left(sTag,Len(sTag)-1) 560 561 ' check for forbidden tags in paragraphs 562 sTagFormat = TagFormatIsCorrect(sTagName, TE.ParaStyleName) 563 If sTagFormat <> "" Then 564 Terminate(sTagName+" element has wrong paragraph style ("+TE.ParaStyleName+")."+chr(13)+"Must be "+sTagFormat,Token) 565 End If 566 567 sDim = ubound(aInlineTagsOpen())+1 568 Redim Preserve aInlineTagsOpen(sDim) as String 569 aInlineTagsOpen(sDim)=sTagName 570 571 ElseIf Left(sTag,1)="_" Then ' a tag ends, all other cases are empty tags 572 573 sTagName = Right(sTag,Len(sTag)-1) 574 575 ' check for forbidden tags in paragraphs 576 sTagFormat = TagFormatIsCorrect(sTagName, TE.ParaStyleName) 577 If sTagFormat <> "" Then 578 Terminate(sTagName+" element has wrong paragraph style ("+TE.ParaStyleName+")."+chr(13)+"Must be "+sTagFormat,Token) 579 End If 580 581 If ubound(aInlineTagsOpen()) > 0 Then 582 If aInlineTagsOpen(ubound(aInlineTagsOpen())) <> sTagName Then 583 Terminate("Inline Element "+aInlineTagsOpen(ubound(aInlineTagsOpen()))+" not closed",Token) 584 End If 585 sDim = ubound(aInlineTagsOpen())-1 586 Else 587 Terminate("No opening tag for "+sTagName,Token) 588 End If 589 Redim Preserve aInlineTagsOpen(sDim) as String 590 591 Else ' empty tag 592 sTagName = sTag 593 sTagFormat = TagFormatIsCorrect(sTagName, TE.ParaStyleName) 594 If sTagFormat <> "" Then 595 Terminate(sTagName+" element has wrong paragraph style ("+TE.ParaStyleName+")."+chr(13)+"Must be "+sTagFormat,Token) 596 End If 597 598 EndIf 599 ElseIf (i > 1) AND (Trim(Token.String) <> "") Then 600 If aInlineTagsOpen(ubound(aInlineTagsOpen())) = "SWITCHINLINE" Then 601 Terminate("No text allowed here.",Token) 602 End If 603 End If 604 Next 605 606 If ubound(aInlineTagsOpen()) > 0 Then 607 Terminate("Inline Element "+aInlineTagsOpen(ubound(aInlineTagsOpen()))+" not closed",Token) 608 End If 609 610 End If 611End Sub 612 613'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 614' CHECK FOR CORRECT TAGS 615'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 616Sub CheckTags(TE As Object) 617 If (Left(TE.ParaStyleName,8) = "hlp_aux_" AND TE.ParaStyleName <> "hlp_aux_bookmark") Then 618 619 TP = TE.createEnumeration 620 621 While TP.hasmoreElements 622 TPE = TP.nextElement 623 624 If TPE.supportsService("com.sun.star.text.TextField") Then 625 sTag = TPE.TextField.TextFieldMaster.Name 626 If Right(sTag,1)="_" Then ' a tag starts 627 628 sTagName = Left(sTag,Len(sTag)-1) 629 sDim = ubound(aTagsOpen())+1 630 Redim Preserve aTagsOpen(sDim) as String 631 aTagsOpen(sDim)=sTagName 632 633 ElseIf Left(sTag,1)="_" Then ' a tag ends, all other cases are empty tags 634 635 sTagName = Right(sTag,Len(sTag)-1) 636 If ubound(aTagsOpen()) > 0 Then 637 If aTagsOpen(ubound(aTagsOpen())) <> sTagName Then 638 Terminate("No close tag for "+aTagsOpen(ubound(aTagsOpen())),TPE) 639 Else 640 sDim = ubound(aTagsOpen())-1 641 End If 642 Else 643 Terminate("No opening tag for "+sTagName,TPE) 644 End If 645 Redim Preserve aTagsOpen(sDim) as String 646 647 Else ' empty tags 648 649 EndIf 650 End If 651 Wend 652 End If 653End Sub 654 655'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 656' CHECK FOR CORRECT TAGS IN A TABLE CELL 657'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 658Sub CheckTagsInCell(CE As Object) 659 If (Left(CE.ParaStyleName,8) = "hlp_aux_" AND CE.ParaStyleName <> "hlp_aux_bookmark") Then 660 661 CP = CE.createEnumeration 662 663 While CP.hasmoreElements 664 CPE = CP.nextElement 665 666 If CPE.supportsService("com.sun.star.text.TextField") Then 667 sTag = CPE.TextField.TextFieldMaster.Name 668 If Right(sTag,1)="_" Then ' a tag starts 669 670 sTagName = Left(sTag,Len(sTag)-1) 671 sDim = ubound(aCellTagsOpen())+1 672 Redim Preserve aCellTagsOpen(sDim) as String 673 aCellTagsOpen(sDim)=sTagName 674 675 ElseIf Left(sTag,1)="_" Then ' a tag ends, all other cases are empty tags 676 677 sTagName = Right(sTag,Len(sTag)-1) 678 If ubound(aCellTagsOpen()) > 0 Then 679 If aCellTagsOpen(ubound(aCellTagsOpen())) <> sTagName Then 680 Terminate("No close tag for "+aCellTagsOpen(ubound(aCellTagsOpen())),CPE) 681 Else 682 sDim = ubound(aCellTagsOpen())-1 683 End If 684 Else 685 Terminate("No opening tag for "+sTagName,CPE) 686 End If 687 Redim Preserve aCellTagsOpen(sDim) as String 688 689 EndIf 690 End If 691 Wend 692 End If 693End Sub 694 695</script:module>