lib.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. // Copyright 2016 - 2023 The excelize Authors. All rights reserved. Use of
  2. // this source code is governed by a BSD-style license that can be found in
  3. // the LICENSE file.
  4. //
  5. // Package excelize providing a set of functions that allow you to write to and
  6. // read from XLAM / XLSM / XLSX / XLTM / XLTX files. Supports reading and
  7. // writing spreadsheet documents generated by Microsoft Excel™ 2007 and later.
  8. // Supports complex components by high compatibility, and provided streaming
  9. // API for generating or reading data from a worksheet with huge amounts of
  10. // data. This library needs Go version 1.16 or later.
  11. package excelize
  12. import (
  13. "archive/zip"
  14. "bytes"
  15. "container/list"
  16. "encoding/xml"
  17. "fmt"
  18. "io"
  19. "math/big"
  20. "os"
  21. "regexp"
  22. "strconv"
  23. "strings"
  24. )
  25. // ReadZipReader extract spreadsheet with given options.
  26. func (f *File) ReadZipReader(r *zip.Reader) (map[string][]byte, int, error) {
  27. var (
  28. err error
  29. docPart = map[string]string{
  30. "[content_types].xml": defaultXMLPathContentTypes,
  31. "xl/sharedstrings.xml": defaultXMLPathSharedStrings,
  32. }
  33. fileList = make(map[string][]byte, len(r.File))
  34. worksheets int
  35. unzipSize int64
  36. )
  37. for _, v := range r.File {
  38. fileSize := v.FileInfo().Size()
  39. unzipSize += fileSize
  40. if unzipSize > f.options.UnzipSizeLimit {
  41. return fileList, worksheets, newUnzipSizeLimitError(f.options.UnzipSizeLimit)
  42. }
  43. fileName := strings.ReplaceAll(v.Name, "\\", "/")
  44. if partName, ok := docPart[strings.ToLower(fileName)]; ok {
  45. fileName = partName
  46. }
  47. if strings.EqualFold(fileName, defaultXMLPathSharedStrings) && fileSize > f.options.UnzipXMLSizeLimit {
  48. if tempFile, err := f.unzipToTemp(v); err == nil {
  49. f.tempFiles.Store(fileName, tempFile)
  50. continue
  51. }
  52. }
  53. if strings.HasPrefix(fileName, "xl/worksheets/sheet") {
  54. worksheets++
  55. if fileSize > f.options.UnzipXMLSizeLimit && !v.FileInfo().IsDir() {
  56. if tempFile, err := f.unzipToTemp(v); err == nil {
  57. f.tempFiles.Store(fileName, tempFile)
  58. continue
  59. }
  60. }
  61. }
  62. if fileList[fileName], err = readFile(v); err != nil {
  63. return nil, 0, err
  64. }
  65. }
  66. return fileList, worksheets, nil
  67. }
  68. // unzipToTemp unzip the zip entity to the system temporary directory and
  69. // returned the unzipped file path.
  70. func (f *File) unzipToTemp(zipFile *zip.File) (string, error) {
  71. tmp, err := os.CreateTemp(os.TempDir(), "excelize-")
  72. if err != nil {
  73. return "", err
  74. }
  75. rc, err := zipFile.Open()
  76. if err != nil {
  77. return tmp.Name(), err
  78. }
  79. if _, err = io.Copy(tmp, rc); err != nil {
  80. return tmp.Name(), err
  81. }
  82. if err = rc.Close(); err != nil {
  83. return tmp.Name(), err
  84. }
  85. return tmp.Name(), tmp.Close()
  86. }
  87. // readXML provides a function to read XML content as bytes.
  88. func (f *File) readXML(name string) []byte {
  89. if content, _ := f.Pkg.Load(name); content != nil {
  90. return content.([]byte)
  91. }
  92. if content, ok := f.streams[name]; ok {
  93. return content.rawData.buf.Bytes()
  94. }
  95. return []byte{}
  96. }
  97. // readBytes read file as bytes by given path.
  98. func (f *File) readBytes(name string) []byte {
  99. content := f.readXML(name)
  100. if len(content) != 0 {
  101. return content
  102. }
  103. file, err := f.readTemp(name)
  104. if err != nil {
  105. return content
  106. }
  107. content, _ = io.ReadAll(file)
  108. f.Pkg.Store(name, content)
  109. _ = file.Close()
  110. return content
  111. }
  112. // readTemp read file from system temporary directory by given path.
  113. func (f *File) readTemp(name string) (file *os.File, err error) {
  114. path, ok := f.tempFiles.Load(name)
  115. if !ok {
  116. return
  117. }
  118. file, err = os.Open(path.(string))
  119. return
  120. }
  121. // saveFileList provides a function to update given file content in file list
  122. // of spreadsheet.
  123. func (f *File) saveFileList(name string, content []byte) {
  124. f.Pkg.Store(name, append([]byte(xml.Header), content...))
  125. }
  126. // Read file content as string in an archive file.
  127. func readFile(file *zip.File) ([]byte, error) {
  128. rc, err := file.Open()
  129. if err != nil {
  130. return nil, err
  131. }
  132. dat := make([]byte, 0, file.FileInfo().Size())
  133. buff := bytes.NewBuffer(dat)
  134. _, _ = io.Copy(buff, rc)
  135. return buff.Bytes(), rc.Close()
  136. }
  137. // SplitCellName splits cell name to column name and row number.
  138. //
  139. // Example:
  140. //
  141. // excelize.SplitCellName("AK74") // return "AK", 74, nil
  142. func SplitCellName(cell string) (string, int, error) {
  143. alpha := func(r rune) bool {
  144. return ('A' <= r && r <= 'Z') || ('a' <= r && r <= 'z') || (r == 36)
  145. }
  146. if strings.IndexFunc(cell, alpha) == 0 {
  147. i := strings.LastIndexFunc(cell, alpha)
  148. if i >= 0 && i < len(cell)-1 {
  149. col, rowStr := strings.ReplaceAll(cell[:i+1], "$", ""), cell[i+1:]
  150. if row, err := strconv.Atoi(rowStr); err == nil && row > 0 {
  151. return col, row, nil
  152. }
  153. }
  154. }
  155. return "", -1, newInvalidCellNameError(cell)
  156. }
  157. // JoinCellName joins cell name from column name and row number.
  158. func JoinCellName(col string, row int) (string, error) {
  159. normCol := strings.Map(func(rune rune) rune {
  160. switch {
  161. case 'A' <= rune && rune <= 'Z':
  162. return rune
  163. case 'a' <= rune && rune <= 'z':
  164. return rune - 32
  165. }
  166. return -1
  167. }, col)
  168. if len(col) == 0 || len(col) != len(normCol) {
  169. return "", newInvalidColumnNameError(col)
  170. }
  171. if row < 1 {
  172. return "", newInvalidRowNumberError(row)
  173. }
  174. return normCol + strconv.Itoa(row), nil
  175. }
  176. // ColumnNameToNumber provides a function to convert Excel sheet column name
  177. // (case-insensitive) to int. The function returns an error if column name
  178. // incorrect.
  179. //
  180. // Example:
  181. //
  182. // excelize.ColumnNameToNumber("AK") // returns 37, nil
  183. func ColumnNameToNumber(name string) (int, error) {
  184. if len(name) == 0 {
  185. return -1, newInvalidColumnNameError(name)
  186. }
  187. col := 0
  188. multi := 1
  189. for i := len(name) - 1; i >= 0; i-- {
  190. r := name[i]
  191. if r >= 'A' && r <= 'Z' {
  192. col += int(r-'A'+1) * multi
  193. } else if r >= 'a' && r <= 'z' {
  194. col += int(r-'a'+1) * multi
  195. } else {
  196. return -1, newInvalidColumnNameError(name)
  197. }
  198. multi *= 26
  199. }
  200. if col > MaxColumns {
  201. return -1, ErrColumnNumber
  202. }
  203. return col, nil
  204. }
  205. // ColumnNumberToName provides a function to convert the integer to Excel
  206. // sheet column title.
  207. //
  208. // Example:
  209. //
  210. // excelize.ColumnNumberToName(37) // returns "AK", nil
  211. func ColumnNumberToName(num int) (string, error) {
  212. if num < MinColumns || num > MaxColumns {
  213. return "", ErrColumnNumber
  214. }
  215. var col string
  216. for num > 0 {
  217. col = string(rune((num-1)%26+65)) + col
  218. num = (num - 1) / 26
  219. }
  220. return col, nil
  221. }
  222. // CellNameToCoordinates converts alphanumeric cell name to [X, Y] coordinates
  223. // or returns an error.
  224. //
  225. // Example:
  226. //
  227. // excelize.CellNameToCoordinates("A1") // returns 1, 1, nil
  228. // excelize.CellNameToCoordinates("Z3") // returns 26, 3, nil
  229. func CellNameToCoordinates(cell string) (int, int, error) {
  230. colName, row, err := SplitCellName(cell)
  231. if err != nil {
  232. return -1, -1, newCellNameToCoordinatesError(cell, err)
  233. }
  234. if row > TotalRows {
  235. return -1, -1, ErrMaxRows
  236. }
  237. col, err := ColumnNameToNumber(colName)
  238. return col, row, err
  239. }
  240. // CoordinatesToCellName converts [X, Y] coordinates to alpha-numeric cell
  241. // name or returns an error.
  242. //
  243. // Example:
  244. //
  245. // excelize.CoordinatesToCellName(1, 1) // returns "A1", nil
  246. // excelize.CoordinatesToCellName(1, 1, true) // returns "$A$1", nil
  247. func CoordinatesToCellName(col, row int, abs ...bool) (string, error) {
  248. if col < 1 || row < 1 {
  249. return "", fmt.Errorf("invalid cell reference [%d, %d]", col, row)
  250. }
  251. sign := ""
  252. for _, a := range abs {
  253. if a {
  254. sign = "$"
  255. }
  256. }
  257. colName, err := ColumnNumberToName(col)
  258. return sign + colName + sign + strconv.Itoa(row), err
  259. }
  260. // rangeRefToCoordinates provides a function to convert range reference to a
  261. // pair of coordinates.
  262. func rangeRefToCoordinates(ref string) ([]int, error) {
  263. rng := strings.Split(strings.ReplaceAll(ref, "$", ""), ":")
  264. if len(rng) < 2 {
  265. return nil, ErrParameterInvalid
  266. }
  267. return cellRefsToCoordinates(rng[0], rng[1])
  268. }
  269. // cellRefsToCoordinates provides a function to convert cell range to a
  270. // pair of coordinates.
  271. func cellRefsToCoordinates(firstCell, lastCell string) ([]int, error) {
  272. coordinates := make([]int, 4)
  273. var err error
  274. coordinates[0], coordinates[1], err = CellNameToCoordinates(firstCell)
  275. if err != nil {
  276. return coordinates, err
  277. }
  278. coordinates[2], coordinates[3], err = CellNameToCoordinates(lastCell)
  279. return coordinates, err
  280. }
  281. // sortCoordinates provides a function to correct the cell range, such
  282. // correct C1:B3 to B1:C3.
  283. func sortCoordinates(coordinates []int) error {
  284. if len(coordinates) != 4 {
  285. return ErrCoordinates
  286. }
  287. if coordinates[2] < coordinates[0] {
  288. coordinates[2], coordinates[0] = coordinates[0], coordinates[2]
  289. }
  290. if coordinates[3] < coordinates[1] {
  291. coordinates[3], coordinates[1] = coordinates[1], coordinates[3]
  292. }
  293. return nil
  294. }
  295. // coordinatesToRangeRef provides a function to convert a pair of coordinates
  296. // to range reference.
  297. func (f *File) coordinatesToRangeRef(coordinates []int, abs ...bool) (string, error) {
  298. if len(coordinates) != 4 {
  299. return "", ErrCoordinates
  300. }
  301. firstCell, err := CoordinatesToCellName(coordinates[0], coordinates[1], abs...)
  302. if err != nil {
  303. return "", err
  304. }
  305. lastCell, err := CoordinatesToCellName(coordinates[2], coordinates[3], abs...)
  306. if err != nil {
  307. return "", err
  308. }
  309. return firstCell + ":" + lastCell, err
  310. }
  311. // getDefinedNameRefTo convert defined name to reference range.
  312. func (f *File) getDefinedNameRefTo(definedNameName string, currentSheet string) (refTo string) {
  313. var workbookRefTo, worksheetRefTo string
  314. for _, definedName := range f.GetDefinedName() {
  315. if definedName.Name == definedNameName {
  316. // worksheet scope takes precedence over scope workbook when both definedNames exist
  317. if definedName.Scope == "Workbook" {
  318. workbookRefTo = definedName.RefersTo
  319. }
  320. if definedName.Scope == currentSheet {
  321. worksheetRefTo = definedName.RefersTo
  322. }
  323. }
  324. }
  325. refTo = workbookRefTo
  326. if worksheetRefTo != "" {
  327. refTo = worksheetRefTo
  328. }
  329. return
  330. }
  331. // flatSqref convert reference sequence to cell reference list.
  332. func (f *File) flatSqref(sqref string) (cells map[int][][]int, err error) {
  333. var coordinates []int
  334. cells = make(map[int][][]int)
  335. for _, ref := range strings.Fields(sqref) {
  336. rng := strings.Split(ref, ":")
  337. switch len(rng) {
  338. case 1:
  339. var col, row int
  340. col, row, err = CellNameToCoordinates(rng[0])
  341. if err != nil {
  342. return
  343. }
  344. cells[col] = append(cells[col], []int{col, row})
  345. case 2:
  346. if coordinates, err = rangeRefToCoordinates(ref); err != nil {
  347. return
  348. }
  349. _ = sortCoordinates(coordinates)
  350. for c := coordinates[0]; c <= coordinates[2]; c++ {
  351. for r := coordinates[1]; r <= coordinates[3]; r++ {
  352. cells[c] = append(cells[c], []int{c, r})
  353. }
  354. }
  355. }
  356. }
  357. return
  358. }
  359. // inCoordinates provides a method to check if a coordinate is present in
  360. // coordinates array, and return the index of its location, otherwise
  361. // return -1.
  362. func inCoordinates(a [][]int, x []int) int {
  363. for idx, n := range a {
  364. if x[0] == n[0] && x[1] == n[1] {
  365. return idx
  366. }
  367. }
  368. return -1
  369. }
  370. // inStrSlice provides a method to check if an element is present in an array,
  371. // and return the index of its location, otherwise return -1.
  372. func inStrSlice(a []string, x string, caseSensitive bool) int {
  373. for idx, n := range a {
  374. if !caseSensitive && strings.EqualFold(x, n) {
  375. return idx
  376. }
  377. if x == n {
  378. return idx
  379. }
  380. }
  381. return -1
  382. }
  383. // inFloat64Slice provides a method to check if an element is present in a
  384. // float64 array, and return the index of its location, otherwise return -1.
  385. func inFloat64Slice(a []float64, x float64) int {
  386. for idx, n := range a {
  387. if x == n {
  388. return idx
  389. }
  390. }
  391. return -1
  392. }
  393. // boolPtr returns a pointer to a bool with the given value.
  394. func boolPtr(b bool) *bool { return &b }
  395. // intPtr returns a pointer to an int with the given value.
  396. func intPtr(i int) *int { return &i }
  397. // uintPtr returns a pointer to an int with the given value.
  398. func uintPtr(i uint) *uint { return &i }
  399. // float64Ptr returns a pointer to a float64 with the given value.
  400. func float64Ptr(f float64) *float64 { return &f }
  401. // stringPtr returns a pointer to a string with the given value.
  402. func stringPtr(s string) *string { return &s }
  403. // MarshalXML convert the boolean data type to literal values 0 or 1 on
  404. // serialization.
  405. func (avb attrValBool) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
  406. attr := xml.Attr{
  407. Name: xml.Name{
  408. Space: start.Name.Space,
  409. Local: "val",
  410. },
  411. Value: "0",
  412. }
  413. if avb.Val != nil {
  414. if *avb.Val {
  415. attr.Value = "1"
  416. } else {
  417. attr.Value = "0"
  418. }
  419. }
  420. start.Attr = []xml.Attr{attr}
  421. if err := e.EncodeToken(start); err != nil {
  422. return err
  423. }
  424. return e.EncodeToken(start.End())
  425. }
  426. // UnmarshalXML convert the literal values true, false, 1, 0 of the XML
  427. // attribute to boolean data type on deserialization.
  428. func (avb *attrValBool) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
  429. for {
  430. t, err := d.Token()
  431. if err != nil {
  432. return err
  433. }
  434. found := false
  435. switch t.(type) {
  436. case xml.StartElement:
  437. return ErrAttrValBool
  438. case xml.EndElement:
  439. found = true
  440. }
  441. if found {
  442. break
  443. }
  444. }
  445. for _, attr := range start.Attr {
  446. if attr.Name.Local == "val" {
  447. if attr.Value == "" {
  448. val := true
  449. avb.Val = &val
  450. } else {
  451. val, err := strconv.ParseBool(attr.Value)
  452. if err != nil {
  453. return err
  454. }
  455. avb.Val = &val
  456. }
  457. return nil
  458. }
  459. }
  460. defaultVal := true
  461. avb.Val = &defaultVal
  462. return nil
  463. }
  464. // namespaceStrictToTransitional provides a method to convert Strict and
  465. // Transitional namespaces.
  466. func namespaceStrictToTransitional(content []byte) []byte {
  467. namespaceTranslationDic := map[string]string{
  468. StrictNameSpaceDocumentPropertiesVariantTypes: NameSpaceDocumentPropertiesVariantTypes.Value,
  469. StrictNameSpaceDrawingMLMain: NameSpaceDrawingMLMain,
  470. StrictNameSpaceExtendedProperties: NameSpaceExtendedProperties,
  471. StrictNameSpaceSpreadSheet: NameSpaceSpreadSheet.Value,
  472. StrictSourceRelationship: SourceRelationship.Value,
  473. StrictSourceRelationshipChart: SourceRelationshipChart,
  474. StrictSourceRelationshipComments: SourceRelationshipComments,
  475. StrictSourceRelationshipExtendProperties: SourceRelationshipExtendProperties,
  476. StrictSourceRelationshipImage: SourceRelationshipImage,
  477. StrictSourceRelationshipOfficeDocument: SourceRelationshipOfficeDocument,
  478. }
  479. for s, n := range namespaceTranslationDic {
  480. content = bytesReplace(content, []byte(s), []byte(n), -1)
  481. }
  482. return content
  483. }
  484. // bytesReplace replace source bytes with given target.
  485. func bytesReplace(s, source, target []byte, n int) []byte {
  486. if n == 0 {
  487. return s
  488. }
  489. if len(source) < len(target) {
  490. return bytes.Replace(s, source, target, n)
  491. }
  492. if n < 0 {
  493. n = len(s)
  494. }
  495. var wid, i, j, w int
  496. for i, j = 0, 0; i < len(s) && j < n; j++ {
  497. wid = bytes.Index(s[i:], source)
  498. if wid < 0 {
  499. break
  500. }
  501. w += copy(s[w:], s[i:i+wid])
  502. w += copy(s[w:], target)
  503. i += wid + len(source)
  504. }
  505. w += copy(s[w:], s[i:])
  506. return s[:w]
  507. }
  508. // genSheetPasswd provides a method to generate password for worksheet
  509. // protection by given plaintext. When an Excel sheet is being protected with
  510. // a password, a 16-bit (two byte) long hash is generated. To verify a
  511. // password, it is compared to the hash. Obviously, if the input data volume
  512. // is great, numerous passwords will match the same hash. Here is the
  513. // algorithm to create the hash value:
  514. //
  515. // take the ASCII values of all characters shift left the first character 1 bit,
  516. // the second 2 bits and so on (use only the lower 15 bits and rotate all higher bits,
  517. // the highest bit of the 16-bit value is always 0 [signed short])
  518. // XOR all these values
  519. // XOR the count of characters
  520. // XOR the constant 0xCE4B
  521. func genSheetPasswd(plaintext string) string {
  522. var password int64 = 0x0000
  523. var charPos uint = 1
  524. for _, v := range plaintext {
  525. value := int64(v) << charPos
  526. charPos++
  527. rotatedBits := value >> 15 // rotated bits beyond bit 15
  528. value &= 0x7fff // first 15 bits
  529. password ^= value | rotatedBits
  530. }
  531. password ^= int64(len(plaintext))
  532. password ^= 0xCE4B
  533. return strings.ToUpper(strconv.FormatInt(password, 16))
  534. }
  535. // getRootElement extract root element attributes by given XML decoder.
  536. func getRootElement(d *xml.Decoder) []xml.Attr {
  537. tokenIdx := 0
  538. for {
  539. token, _ := d.Token()
  540. if token == nil {
  541. break
  542. }
  543. switch startElement := token.(type) {
  544. case xml.StartElement:
  545. tokenIdx++
  546. if tokenIdx == 1 {
  547. return startElement.Attr
  548. }
  549. }
  550. }
  551. return nil
  552. }
  553. // genXMLNamespace generate serialized XML attributes with a multi namespace
  554. // by given element attributes.
  555. func genXMLNamespace(attr []xml.Attr) string {
  556. var rootElement string
  557. for _, v := range attr {
  558. if lastSpace := getXMLNamespace(v.Name.Space, attr); lastSpace != "" {
  559. if lastSpace == NameSpaceXML {
  560. lastSpace = "xml"
  561. }
  562. rootElement += fmt.Sprintf("%s:%s=\"%s\" ", lastSpace, v.Name.Local, v.Value)
  563. continue
  564. }
  565. rootElement += fmt.Sprintf("%s=\"%s\" ", v.Name.Local, v.Value)
  566. }
  567. return strings.TrimSpace(rootElement) + ">"
  568. }
  569. // getXMLNamespace extract XML namespace from specified element name and attributes.
  570. func getXMLNamespace(space string, attr []xml.Attr) string {
  571. for _, attribute := range attr {
  572. if attribute.Value == space {
  573. return attribute.Name.Local
  574. }
  575. }
  576. return space
  577. }
  578. // replaceNameSpaceBytes provides a function to replace the XML root element
  579. // attribute by the given component part path and XML content.
  580. func (f *File) replaceNameSpaceBytes(path string, contentMarshal []byte) []byte {
  581. sourceXmlns := []byte(`xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
  582. targetXmlns := []byte(templateNamespaceIDMap)
  583. if attr, ok := f.xmlAttr[path]; ok {
  584. targetXmlns = []byte(genXMLNamespace(attr))
  585. }
  586. return bytesReplace(contentMarshal, sourceXmlns, bytes.ReplaceAll(targetXmlns, []byte(" mc:Ignorable=\"r\""), []byte{}), -1)
  587. }
  588. // addNameSpaces provides a function to add an XML attribute by the given
  589. // component part path.
  590. func (f *File) addNameSpaces(path string, ns xml.Attr) {
  591. exist := false
  592. mc := false
  593. ignore := -1
  594. if attr, ok := f.xmlAttr[path]; ok {
  595. for i, attribute := range attr {
  596. if attribute.Name.Local == ns.Name.Local && attribute.Name.Space == ns.Name.Space {
  597. exist = true
  598. }
  599. if attribute.Name.Local == "Ignorable" && getXMLNamespace(attribute.Name.Space, attr) == "mc" {
  600. ignore = i
  601. }
  602. if attribute.Name.Local == "mc" && attribute.Name.Space == "xmlns" {
  603. mc = true
  604. }
  605. }
  606. }
  607. if !exist {
  608. f.xmlAttr[path] = append(f.xmlAttr[path], ns)
  609. if !mc {
  610. f.xmlAttr[path] = append(f.xmlAttr[path], SourceRelationshipCompatibility)
  611. }
  612. if ignore == -1 {
  613. f.xmlAttr[path] = append(f.xmlAttr[path], xml.Attr{
  614. Name: xml.Name{Local: "Ignorable", Space: "mc"},
  615. Value: ns.Name.Local,
  616. })
  617. return
  618. }
  619. f.setIgnorableNameSpace(path, ignore, ns)
  620. }
  621. }
  622. // setIgnorableNameSpace provides a function to set XML namespace as ignorable
  623. // by the given attribute.
  624. func (f *File) setIgnorableNameSpace(path string, index int, ns xml.Attr) {
  625. ignorableNS := []string{"c14", "cdr14", "a14", "pic14", "x14", "xdr14", "x14ac", "dsp", "mso14", "dgm14", "x15", "x12ac", "x15ac", "xr", "xr2", "xr3", "xr4", "xr5", "xr6", "xr7", "xr8", "xr9", "xr10", "xr11", "xr12", "xr13", "xr14", "xr15", "x15", "x16", "x16r2", "mo", "mx", "mv", "o", "v"}
  626. if inStrSlice(strings.Fields(f.xmlAttr[path][index].Value), ns.Name.Local, true) == -1 && inStrSlice(ignorableNS, ns.Name.Local, true) != -1 {
  627. f.xmlAttr[path][index].Value = strings.TrimSpace(fmt.Sprintf("%s %s", f.xmlAttr[path][index].Value, ns.Name.Local))
  628. }
  629. }
  630. // addSheetNameSpace add XML attribute for worksheet.
  631. func (f *File) addSheetNameSpace(sheet string, ns xml.Attr) {
  632. name, _ := f.getSheetXMLPath(sheet)
  633. f.addNameSpaces(name, ns)
  634. }
  635. // isNumeric determines whether an expression is a valid numeric type and get
  636. // the precision for the numeric.
  637. func isNumeric(s string) (bool, int, float64) {
  638. if strings.Contains(s, "_") {
  639. return false, 0, 0
  640. }
  641. var decimal big.Float
  642. _, ok := decimal.SetString(s)
  643. if !ok {
  644. return false, 0, 0
  645. }
  646. var noScientificNotation string
  647. flt, _ := decimal.Float64()
  648. noScientificNotation = strconv.FormatFloat(flt, 'f', -1, 64)
  649. return true, len(strings.ReplaceAll(noScientificNotation, ".", "")), flt
  650. }
  651. var (
  652. bstrExp = regexp.MustCompile(`_x[a-fA-F\d]{4}_`)
  653. bstrEscapeExp = regexp.MustCompile(`x[a-fA-F\d]{4}_`)
  654. )
  655. // bstrUnmarshal parses the binary basic string, this will trim escaped string
  656. // literal which not permitted in an XML 1.0 document. The basic string
  657. // variant type can store any valid Unicode character. Unicode's characters
  658. // that cannot be directly represented in XML as defined by the XML 1.0
  659. // specification, shall be escaped using the Unicode numerical character
  660. // representation escape character format _xHHHH_, where H represents a
  661. // hexadecimal character in the character's value. For example: The Unicode
  662. // character 8 is not permitted in an XML 1.0 document, so it shall be
  663. // escaped as _x0008_. To store the literal form of an escape sequence, the
  664. // initial underscore shall itself be escaped (i.e. stored as _x005F_). For
  665. // example: The string literal _x0008_ would be stored as _x005F_x0008_.
  666. func bstrUnmarshal(s string) (result string) {
  667. matches, l, cursor := bstrExp.FindAllStringSubmatchIndex(s, -1), len(s), 0
  668. for _, match := range matches {
  669. result += s[cursor:match[0]]
  670. subStr := s[match[0]:match[1]]
  671. if subStr == "_x005F_" {
  672. cursor = match[1]
  673. result += "_"
  674. continue
  675. }
  676. if bstrExp.MatchString(subStr) {
  677. cursor = match[1]
  678. v, _ := strconv.Unquote(`"\u` + s[match[0]+2:match[1]-1] + `"`)
  679. result += v
  680. }
  681. }
  682. if cursor < l {
  683. result += s[cursor:]
  684. }
  685. return result
  686. }
  687. // bstrMarshal encode the escaped string literal which not permitted in an XML
  688. // 1.0 document.
  689. func bstrMarshal(s string) (result string) {
  690. matches, l, cursor := bstrExp.FindAllStringSubmatchIndex(s, -1), len(s), 0
  691. for _, match := range matches {
  692. result += s[cursor:match[0]]
  693. subStr := s[match[0]:match[1]]
  694. if subStr == "_x005F_" {
  695. cursor = match[1]
  696. if match[1]+6 <= l && bstrEscapeExp.MatchString(s[match[1]:match[1]+6]) {
  697. _, err := strconv.Unquote(`"\u` + s[match[1]+1:match[1]+5] + `"`)
  698. if err == nil {
  699. result += subStr + "x005F" + subStr
  700. continue
  701. }
  702. }
  703. result += subStr + "x005F_"
  704. continue
  705. }
  706. if bstrExp.MatchString(subStr) {
  707. cursor = match[1]
  708. if _, err := strconv.Unquote(`"\u` + s[match[0]+2:match[1]-1] + `"`); err == nil {
  709. result += "_x005F" + subStr
  710. continue
  711. }
  712. }
  713. }
  714. if cursor < l {
  715. result += s[cursor:]
  716. }
  717. return result
  718. }
  719. // Stack defined an abstract data type that serves as a collection of elements.
  720. type Stack struct {
  721. list *list.List
  722. }
  723. // NewStack create a new stack.
  724. func NewStack() *Stack {
  725. l := list.New()
  726. return &Stack{l}
  727. }
  728. // Push a value onto the top of the stack.
  729. func (stack *Stack) Push(value interface{}) {
  730. stack.list.PushBack(value)
  731. }
  732. // Pop the top item of the stack and return it.
  733. func (stack *Stack) Pop() interface{} {
  734. e := stack.list.Back()
  735. if e != nil {
  736. stack.list.Remove(e)
  737. return e.Value
  738. }
  739. return nil
  740. }
  741. // Peek view the top item on the stack.
  742. func (stack *Stack) Peek() interface{} {
  743. e := stack.list.Back()
  744. if e != nil {
  745. return e.Value
  746. }
  747. return nil
  748. }
  749. // Len return the number of items in the stack.
  750. func (stack *Stack) Len() int {
  751. return stack.list.Len()
  752. }
  753. // Empty the stack.
  754. func (stack *Stack) Empty() bool {
  755. return stack.list.Len() == 0
  756. }