[{"data":1,"prerenderedAt":2968},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Finspect-the-xml-inside-an-xlsx-file-with-python":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Finspect-the-xml-inside-an-xlsx-file-with-python":2932,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Finspect-the-xml-inside-an-xlsx-file-with-python":2941,"children:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Finspect-the-xml-inside-an-xlsx-file-with-python":2946,"related:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Finspect-the-xml-inside-an-xlsx-file-with-python":2947},{"id":4,"title":5,"body":6,"dateModified":2899,"datePublished":2899,"description":2900,"extension":2901,"faq":2902,"keyword":2911,"kind":2912,"meta":2913,"navigation":75,"path":2921,"seo":2922,"slug":2925,"stem":2926,"topics":2927,"type":2930,"__hash__":2931},"docs\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Finspect-the-xml-inside-an-xlsx-file-with-python\u002Findex.md","Inspect the XML Inside an .xlsx File with Python",{"type":7,"value":8,"toc":2886},"minimark",[9,24,29,44,48,156,211,379,383,394,722,744,748,974,1060,1073,1246,1266,1606,1610,1637,2092,2116,2120,2123,2259,2280,2284,2287,2599,2616,2722,2726,2787,2791,2821,2825,2831,2837,2843,2849,2853,2882],[10,11,12,13,17,18,23],"p",{},"Most of the time openpyxl and pandas hide the file format completely, which is the point of using them. But some questions can only be answered by looking at what is actually in the file: why Excel says a generated workbook needs repairing, whether a formula has a cached result, what number format a cell really has, which tool produced the file, or what changed between two versions that look identical on screen. An ",[14,15,16],"code",{},".xlsx"," file is a ZIP archive of XML documents — the Office Open XML format — and the standard library can open it, list its parts and parse any of them. This page is a short field guide to doing that. It belongs to ",[19,20,22],"a",{"href":21},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002F","Handling Excel File Formats and Conversions",".",[25,26,28],"h2",{"id":27},"prerequisites","Prerequisites",[10,30,31,32,35,36,39,40,43],{},"Nothing to install: ",[14,33,34],{},"zipfile"," and ",[14,37,38],{},"xml.etree.ElementTree"," are part of Python. The examples inspect ",[14,41,42],{},"orders.xlsx",", a small workbook with text, numbers, formulas, booleans, dates and two custom number formats, written by XlsxWriter — which, like Excel, stores text in a shared-strings table.",[25,45,47],{"id":46},"step-1-list-the-parts","Step 1 — List the parts",[49,50,55],"pre",{"className":51,"code":52,"language":53,"meta":54,"style":54},"language-python shiki shiki-themes github-light github-dark-high-contrast","import zipfile\n\nz = zipfile.ZipFile(\"orders.xlsx\")\nfor info in z.infolist():\n    print(f\"{info.filename:32} {info.file_size:>6} bytes\")\n","python","",[14,56,57,70,77,96,111],{"__ignoreMap":54},[58,59,62,66],"span",{"class":60,"line":61},"line",1,[58,63,65],{"class":64},"s-kum","import",[58,67,69],{"class":68},"skGVy"," zipfile\n",[58,71,73],{"class":60,"line":72},2,[58,74,76],{"emptyLinePlaceholder":75},true,"\n",[58,78,80,83,86,89,93],{"class":60,"line":79},3,[58,81,82],{"class":68},"z ",[58,84,85],{"class":64},"=",[58,87,88],{"class":68}," zipfile.ZipFile(",[58,90,92],{"class":91},"srMev","\"orders.xlsx\"",[58,94,95],{"class":68},")\n",[58,97,99,102,105,108],{"class":60,"line":98},4,[58,100,101],{"class":64},"for",[58,103,104],{"class":68}," info ",[58,106,107],{"class":64},"in",[58,109,110],{"class":68}," z.infolist():\n",[58,112,114,118,121,124,127,131,134,137,140,143,146,149,151,154],{"class":60,"line":113},5,[58,115,117],{"class":116},"sP0c6","    print",[58,119,120],{"class":68},"(",[58,122,123],{"class":64},"f",[58,125,126],{"class":91},"\"",[58,128,130],{"class":129},"sSjpA","{",[58,132,133],{"class":68},"info.filename",[58,135,136],{"class":64},":32",[58,138,139],{"class":129},"}",[58,141,142],{"class":129}," {",[58,144,145],{"class":68},"info.file_size",[58,147,148],{"class":64},":>6",[58,150,139],{"class":129},[58,152,153],{"class":91}," bytes\"",[58,155,95],{"class":68},[10,157,158,159,162,163,166,167,170,171,35,174,177,178,181,182,185,186,35,189,192,193,196,197,200,201,200,204,200,207,210],{},"The listing is the map of the package. ",[14,160,161],{},"[Content_Types].xml"," declares what each part is; ",[14,164,165],{},"_rels\u002F.rels"," points at the workbook; ",[14,168,169],{},"xl\u002Fworkbook.xml"," lists the sheets; ",[14,172,173],{},"xl\u002Fworksheets\u002Fsheet1.xml",[14,175,176],{},"sheet2.xml"," hold the cells; ",[14,179,180],{},"xl\u002FsharedStrings.xml"," holds text values (if the writer used it); ",[14,183,184],{},"xl\u002Fstyles.xml"," holds fonts, fills, borders and number formats; ",[14,187,188],{},"docProps\u002Fapp.xml",[14,190,191],{},"core.xml"," hold metadata such as the application name and author; the listing above has a ",[14,194,195],{},"sharedStrings.xml"," because XlsxWriter wrote the file. Anything else — ",[14,198,199],{},"xl\u002Fdrawings\u002F",", ",[14,202,203],{},"xl\u002Fcharts\u002F",[14,205,206],{},"xl\u002Fmedia\u002F",[14,208,209],{},"xl\u002FvbaProject.bin"," — means charts, images or macros.",[212,213,221,222,221,226,221,230,221,238,221,248,221,259,221,266,221,271,221,276,221,281,221,285,221,292,221,296,221,300,221,304,221,307,221,310,221,316,221,320,221,324,221,328,221,331,221,336,221,343,221,347,221,351,221,355,221,358,221,363,221,370,221,375],"svg",{"viewBox":214,"role":215,"ariaLabelledBy":216,"xmlns":219,"style":220},"84 0 592 641","img",[217,218],"xml-parts-t","xml-parts-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:592px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[223,224,225],"title",{"id":217},"The parts of an .xlsx package and how they connect",[227,228,229],"desc",{"id":218},"The package starts at [Content_Types].xml and _rels\u002F.rels, which point to xl\u002Fworkbook.xml. The workbook lists sheets and, through its relationships file, points to each worksheet XML. Worksheets refer to shared strings and styles by index.",[231,232],"rect",{"x":233,"y":234,"width":235,"height":236,"fill":237},"84","0","592","641","#ffffff",[231,239],{"x":240,"y":241,"width":242,"height":243,"rx":244,"fill":245,"stroke":246,"style":247},"100.0","16.0","560.0","93.0","12","#e7ebef","var(--line,#cdd5e6)","stroke-width:2px",[249,250,252],"g",{"transform":251},"translate(368.0,29.0) scale(1.000)",[253,254],"path",{"d":255,"fill":256,"stroke":257,"style":258},"M12 2.5l8.5 4.7v9.6L12 21.5l-8.5-4.7V7.2z M3.5 7.2l8.5 4.7 8.5-4.7 M12 11.9v9.6","none","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[260,261,265],"text",{"x":262,"y":263,"style":264},"380.0","75.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","[Content_Types].xml and _rels\u002F.rels",[260,267,270],{"x":262,"y":268,"style":269},"95.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","what each part is; where the workbook lives",[60,272],{"x1":262,"y1":273,"x2":262,"y2":274,"stroke":275,"style":247},"114.0","136.0","var(--brand,#5b5cf0)",[277,278],"polygon",{"points":279,"fill":280},"380.0,140.0 375.0,131.0 385.0,131.0","#5b5cf0",[231,282],{"x":240,"y":283,"width":242,"height":243,"rx":244,"fill":284,"stroke":275,"style":247},"145.0","#f0f4ff",[249,286,288],{"transform":287},"translate(368.0,158.0) scale(1.000)",[253,289],{"d":290,"fill":256,"stroke":291,"style":258},"M6 3h9l4 4v14H6z M15 3v4h4 M9.5 11.5l4.5 6 M14 11.5l-4.5 6","var(--brand-strong,#4338ca)",[260,293,169],{"x":262,"y":294,"style":295},"204.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle",[260,297,299],{"x":262,"y":298,"style":269},"224.0","sheet names, order, defined names",[60,301],{"x1":262,"y1":302,"x2":262,"y2":303,"stroke":275,"style":247},"243.0","265.0",[277,305],{"points":306,"fill":280},"380.0,269.0 375.0,260.0 385.0,260.0",[231,308],{"x":240,"y":309,"width":242,"height":243,"rx":244,"fill":284,"stroke":275,"style":247},"274.0",[249,311,313],{"transform":312},"translate(368.0,287.0) scale(1.000)",[253,314],{"d":315,"fill":256,"stroke":291,"style":258},"M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1 M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1",[260,317,319],{"x":262,"y":318,"style":295},"333.5","xl\u002F_rels\u002Fworkbook.xml.rels",[260,321,323],{"x":262,"y":322,"style":269},"353.0","r:id → worksheets\u002Fsheet1.xml",[60,325],{"x1":262,"y1":326,"x2":262,"y2":327,"stroke":275,"style":247},"372.0","394.0",[277,329],{"points":330,"fill":280},"380.0,398.0 375.0,389.0 385.0,389.0",[231,332],{"x":240,"y":333,"width":242,"height":243,"rx":244,"fill":334,"stroke":335,"style":247},"403.0","#d9f4f1","var(--teal,#0f9488)",[249,337,339],{"transform":338},"translate(368.0,416.0) scale(1.000)",[253,340],{"d":341,"fill":256,"stroke":342,"style":258},"M4 4h16v16H4z M4 9h16 M4 14h16 M10 4v16","var(--teal-ink,#0b6157)",[260,344,173],{"x":262,"y":345,"style":346},"462.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle",[260,348,350],{"x":262,"y":349,"style":269},"482.0","rows and cells: \u003Cc r=\"B2\" t=…>\u003Cv>…\u003C\u002Fv>\u003C\u002Fc>",[60,352],{"x1":262,"y1":353,"x2":262,"y2":354,"stroke":275,"style":247},"501.0","523.0",[277,356],{"points":357,"fill":280},"380.0,527.0 375.0,518.0 385.0,518.0",[231,359],{"x":240,"y":360,"width":242,"height":243,"rx":244,"fill":361,"stroke":362,"style":247},"532.0","#fdefd8","var(--gold,#b4740a)",[249,364,366],{"transform":365},"translate(368.0,545.0) scale(1.000)",[253,367],{"d":368,"fill":256,"stroke":369,"style":258},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14","var(--gold-ink,#7a4e06)",[260,371,374],{"x":262,"y":372,"style":373},"591.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","xl\u002FsharedStrings.xml · xl\u002Fstyles.xml",[260,376,378],{"x":262,"y":377,"style":269},"611.0","text and formats, referenced by index",[25,380,382],{"id":381},"step-2-find-the-file-behind-a-sheet-name","Step 2 — Find the file behind a sheet name",[10,384,385,386,389,390,393],{},"Sheet names live in ",[14,387,388],{},"workbook.xml","; the file that holds each sheet is found through a relationship ID. Do not assume ",[14,391,392],{},"sheet1.xml"," is the first tab — after sheets are reordered or deleted, the numbering no longer matches:",[49,395,397],{"className":51,"code":396,"language":53,"meta":54,"style":54},"import xml.etree.ElementTree as ET\n\nNS = {\n    \"m\": \"http:\u002F\u002Fschemas.openxmlformats.org\u002Fspreadsheetml\u002F2006\u002Fmain\",\n    \"r\": \"http:\u002F\u002Fschemas.openxmlformats.org\u002FofficeDocument\u002F2006\u002Frelationships\",\n    \"rel\": \"http:\u002F\u002Fschemas.openxmlformats.org\u002Fpackage\u002F2006\u002Frelationships\",\n}\n\ndef sheet_parts(z):\n    wb = ET.fromstring(z.read(\"xl\u002Fworkbook.xml\"))\n    rels = ET.fromstring(z.read(\"xl\u002F_rels\u002Fworkbook.xml.rels\"))\n    targets = {r.get(\"Id\"): r.get(\"Target\") for r in rels.findall(\"rel:Relationship\", NS)}\n    out = {}\n    for s in wb.find(\"m:sheets\", NS):\n        target = targets[s.get(f\"{{{NS['r']}}}id\")].lstrip(\"\u002F\")\n        out[s.get(\"name\")] = target if target.startswith(\"xl\u002F\") else \"xl\u002F\" + target\n    return out\n\nparts = sheet_parts(z)\nprint(parts)\n",[14,398,399,412,416,427,441,453,466,472,477,490,510,527,570,581,605,648,688,697,702,713],{"__ignoreMap":54},[58,400,401,403,406,409],{"class":60,"line":61},[58,402,65],{"class":64},[58,404,405],{"class":68}," xml.etree.ElementTree ",[58,407,408],{"class":64},"as",[58,410,411],{"class":116}," ET\n",[58,413,414],{"class":60,"line":72},[58,415,76],{"emptyLinePlaceholder":75},[58,417,418,421,424],{"class":60,"line":79},[58,419,420],{"class":116},"NS",[58,422,423],{"class":64}," =",[58,425,426],{"class":68}," {\n",[58,428,429,432,435,438],{"class":60,"line":98},[58,430,431],{"class":91},"    \"m\"",[58,433,434],{"class":68},": ",[58,436,437],{"class":91},"\"http:\u002F\u002Fschemas.openxmlformats.org\u002Fspreadsheetml\u002F2006\u002Fmain\"",[58,439,440],{"class":68},",\n",[58,442,443,446,448,451],{"class":60,"line":113},[58,444,445],{"class":91},"    \"r\"",[58,447,434],{"class":68},[58,449,450],{"class":91},"\"http:\u002F\u002Fschemas.openxmlformats.org\u002FofficeDocument\u002F2006\u002Frelationships\"",[58,452,440],{"class":68},[58,454,456,459,461,464],{"class":60,"line":455},6,[58,457,458],{"class":91},"    \"rel\"",[58,460,434],{"class":68},[58,462,463],{"class":91},"\"http:\u002F\u002Fschemas.openxmlformats.org\u002Fpackage\u002F2006\u002Frelationships\"",[58,465,440],{"class":68},[58,467,469],{"class":60,"line":468},7,[58,470,471],{"class":68},"}\n",[58,473,475],{"class":60,"line":474},8,[58,476,76],{"emptyLinePlaceholder":75},[58,478,480,483,487],{"class":60,"line":479},9,[58,481,482],{"class":64},"def",[58,484,486],{"class":485},"s_Opv"," sheet_parts",[58,488,489],{"class":68},"(z):\n",[58,491,493,496,498,501,504,507],{"class":60,"line":492},10,[58,494,495],{"class":68},"    wb ",[58,497,85],{"class":64},[58,499,500],{"class":116}," ET",[58,502,503],{"class":68},".fromstring(z.read(",[58,505,506],{"class":91},"\"xl\u002Fworkbook.xml\"",[58,508,509],{"class":68},"))\n",[58,511,513,516,518,520,522,525],{"class":60,"line":512},11,[58,514,515],{"class":68},"    rels ",[58,517,85],{"class":64},[58,519,500],{"class":116},[58,521,503],{"class":68},[58,523,524],{"class":91},"\"xl\u002F_rels\u002Fworkbook.xml.rels\"",[58,526,509],{"class":68},[58,528,530,533,535,538,541,544,547,550,552,555,557,560,563,565,567],{"class":60,"line":529},12,[58,531,532],{"class":68},"    targets ",[58,534,85],{"class":64},[58,536,537],{"class":68}," {r.get(",[58,539,540],{"class":91},"\"Id\"",[58,542,543],{"class":68},"): r.get(",[58,545,546],{"class":91},"\"Target\"",[58,548,549],{"class":68},") ",[58,551,101],{"class":64},[58,553,554],{"class":68}," r ",[58,556,107],{"class":64},[58,558,559],{"class":68}," rels.findall(",[58,561,562],{"class":91},"\"rel:Relationship\"",[58,564,200],{"class":68},[58,566,420],{"class":116},[58,568,569],{"class":68},")}\n",[58,571,573,576,578],{"class":60,"line":572},13,[58,574,575],{"class":68},"    out ",[58,577,85],{"class":64},[58,579,580],{"class":68}," {}\n",[58,582,584,587,590,592,595,598,600,602],{"class":60,"line":583},14,[58,585,586],{"class":64},"    for",[58,588,589],{"class":68}," s ",[58,591,107],{"class":64},[58,593,594],{"class":68}," wb.find(",[58,596,597],{"class":91},"\"m:sheets\"",[58,599,200],{"class":68},[58,601,420],{"class":116},[58,603,604],{"class":68},"):\n",[58,606,608,611,613,616,618,620,623,625,628,631,634,637,640,643,646],{"class":60,"line":607},15,[58,609,610],{"class":68},"        target ",[58,612,85],{"class":64},[58,614,615],{"class":68}," targets[s.get(",[58,617,123],{"class":64},[58,619,126],{"class":91},[58,621,622],{"class":129},"{{{",[58,624,420],{"class":116},[58,626,627],{"class":68},"[",[58,629,630],{"class":91},"'r'",[58,632,633],{"class":68},"]",[58,635,636],{"class":129},"}}}",[58,638,639],{"class":91},"id\"",[58,641,642],{"class":68},")].lstrip(",[58,644,645],{"class":91},"\"\u002F\"",[58,647,95],{"class":68},[58,649,651,654,657,660,662,665,668,671,674,676,679,682,685],{"class":60,"line":650},16,[58,652,653],{"class":68},"        out[s.get(",[58,655,656],{"class":91},"\"name\"",[58,658,659],{"class":68},")] ",[58,661,85],{"class":64},[58,663,664],{"class":68}," target ",[58,666,667],{"class":64},"if",[58,669,670],{"class":68}," target.startswith(",[58,672,673],{"class":91},"\"xl\u002F\"",[58,675,549],{"class":68},[58,677,678],{"class":64},"else",[58,680,681],{"class":91}," \"xl\u002F\"",[58,683,684],{"class":64}," +",[58,686,687],{"class":68}," target\n",[58,689,691,694],{"class":60,"line":690},17,[58,692,693],{"class":64},"    return",[58,695,696],{"class":68}," out\n",[58,698,700],{"class":60,"line":699},18,[58,701,76],{"emptyLinePlaceholder":75},[58,703,705,708,710],{"class":60,"line":704},19,[58,706,707],{"class":68},"parts ",[58,709,85],{"class":64},[58,711,712],{"class":68}," sheet_parts(z)\n",[58,714,716,719],{"class":60,"line":715},20,[58,717,718],{"class":116},"print",[58,720,721],{"class":68},"(parts)\n",[10,723,724,725,727,728,731,732,735,736,739,740,23],{},"Every element in these files lives in an XML namespace, so ElementTree searches need the prefixes in ",[14,726,420],{},". The relationship target is usually relative to ",[14,729,730],{},"xl\u002F"," (",[14,733,734],{},"worksheets\u002Fsheet1.xml","), but some writers use absolute paths starting with ",[14,737,738],{},"\u002Fxl\u002F","; the helper handles both. This is the same lookup openpyxl performs, and a file where it fails is one where openpyxl reports \"0 worksheets found\" — see ",[19,741,743],{"href":742},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-worksheet-index-0-is-invalid-0-worksheets-found\u002F","Fix \"Worksheet index 0 is invalid, 0 worksheets found\"",[25,745,747],{"id":746},"step-3-read-cells-and-their-types","Step 3 — Read cells and their types",[49,749,751],{"className":51,"code":750,"language":53,"meta":54,"style":54},"sheet = ET.fromstring(z.read(parts[\"Orders\"]))\nfor c in sheet.iter(f\"{{{NS['m']}}}c\"):\n    f, v = c.find(\"m:f\", NS), c.find(\"m:v\", NS)\n    print(f\"{c.get('r'):4} t={c.get('t', 'n'):4} s={c.get('s', '0'):2} \"\n          f\"f={(f.text if f is not None else ''):8} v={v.text if v is not None else ''}\")\n",[14,752,753,771,805,834,905],{"__ignoreMap":54},[58,754,755,758,760,762,765,768],{"class":60,"line":61},[58,756,757],{"class":68},"sheet ",[58,759,85],{"class":64},[58,761,500],{"class":116},[58,763,764],{"class":68},".fromstring(z.read(parts[",[58,766,767],{"class":91},"\"Orders\"",[58,769,770],{"class":68},"]))\n",[58,772,773,775,778,780,783,785,787,789,791,793,796,798,800,803],{"class":60,"line":72},[58,774,101],{"class":64},[58,776,777],{"class":68}," c ",[58,779,107],{"class":64},[58,781,782],{"class":68}," sheet.iter(",[58,784,123],{"class":64},[58,786,126],{"class":91},[58,788,622],{"class":129},[58,790,420],{"class":116},[58,792,627],{"class":68},[58,794,795],{"class":91},"'m'",[58,797,633],{"class":68},[58,799,636],{"class":129},[58,801,802],{"class":91},"c\"",[58,804,604],{"class":68},[58,806,807,810,812,815,818,820,822,825,828,830,832],{"class":60,"line":79},[58,808,809],{"class":68},"    f, v ",[58,811,85],{"class":64},[58,813,814],{"class":68}," c.find(",[58,816,817],{"class":91},"\"m:f\"",[58,819,200],{"class":68},[58,821,420],{"class":116},[58,823,824],{"class":68},"), c.find(",[58,826,827],{"class":91},"\"m:v\"",[58,829,200],{"class":68},[58,831,420],{"class":116},[58,833,95],{"class":68},[58,835,836,838,840,842,844,846,849,851,854,857,859,862,864,866,869,871,874,876,878,880,883,885,887,890,892,895,897,900,902],{"class":60,"line":98},[58,837,117],{"class":116},[58,839,120],{"class":68},[58,841,123],{"class":64},[58,843,126],{"class":91},[58,845,130],{"class":129},[58,847,848],{"class":68},"c.get(",[58,850,630],{"class":91},[58,852,853],{"class":68},")",[58,855,856],{"class":64},":4",[58,858,139],{"class":129},[58,860,861],{"class":91}," t=",[58,863,130],{"class":129},[58,865,848],{"class":68},[58,867,868],{"class":91},"'t'",[58,870,200],{"class":68},[58,872,873],{"class":91},"'n'",[58,875,853],{"class":68},[58,877,856],{"class":64},[58,879,139],{"class":129},[58,881,882],{"class":91}," s=",[58,884,130],{"class":129},[58,886,848],{"class":68},[58,888,889],{"class":91},"'s'",[58,891,200],{"class":68},[58,893,894],{"class":91},"'0'",[58,896,853],{"class":68},[58,898,899],{"class":64},":2",[58,901,139],{"class":129},[58,903,904],{"class":91}," \"\n",[58,906,907,910,913,915,918,920,923,926,929,932,935,938,940,943,945,948,950,953,955,958,960,962,964,966,968,970,972],{"class":60,"line":113},[58,908,909],{"class":64},"          f",[58,911,912],{"class":91},"\"f=",[58,914,130],{"class":129},[58,916,917],{"class":68},"(f.text ",[58,919,667],{"class":64},[58,921,922],{"class":68}," f ",[58,924,925],{"class":64},"is",[58,927,928],{"class":64}," not",[58,930,931],{"class":116}," None",[58,933,934],{"class":64}," else",[58,936,937],{"class":91}," ''",[58,939,853],{"class":68},[58,941,942],{"class":64},":8",[58,944,139],{"class":129},[58,946,947],{"class":91}," v=",[58,949,130],{"class":129},[58,951,952],{"class":68},"v.text ",[58,954,667],{"class":64},[58,956,957],{"class":68}," v ",[58,959,925],{"class":64},[58,961,928],{"class":64},[58,963,931],{"class":116},[58,965,934],{"class":64},[58,967,937],{"class":91},[58,969,139],{"class":129},[58,971,126],{"class":91},[58,973,95],{"class":68},[10,975,976,977,980,981,984,985,988,989,992,993,996,997,999,1000,1003,1004,1007,1008,1011,1012,1015,1016,1018,1019,1022,1023,1026,1027,1030,1031,1034,1035,1038,1039,1042,1043,1046,1047,1050,1051,1053,1054,1056,1057,1059],{},"Each ",[14,978,979],{},"\u003Cc>"," element is one cell. ",[14,982,983],{},"r"," is its address, ",[14,986,987],{},"s"," an index into the styles, and ",[14,990,991],{},"t"," the type: ",[14,994,995],{},"n"," (the default when absent) for numbers, ",[14,998,987],{}," for an index into the shared-strings table, ",[14,1001,1002],{},"str"," for a formula's text result, ",[14,1005,1006],{},"inlineStr"," for text stored in the cell itself, ",[14,1009,1010],{},"b"," for booleans (",[14,1013,1014],{},"1","\u002F",[14,1017,234],{},") and ",[14,1020,1021],{},"e"," for errors such as ",[14,1024,1025],{},"#DIV\u002F0!",". A ",[14,1028,1029],{},"\u003Cf>"," child holds a formula and ",[14,1032,1033],{},"\u003Cv>"," its cached result. The output shows the things openpyxl smooths over: the header and product names are ",[14,1036,1037],{},"t=\"s\""," with small integers as values (indexes into the string table), dates are plain numbers (",[14,1040,1041],{},"46266"," is 1 September 2026), ",[14,1044,1045],{},"TRUE"," is ",[14,1048,1049],{},"t=\"b\""," with value ",[14,1052,1014],{},", and the formulas in column D carry a cached ",[14,1055,1033],{}," of ",[14,1058,234],{}," — XlsxWriter's placeholder, not the real product.",[10,1061,1062,1063,1066,1067,1069,1070,1072],{},"Writers differ here, and the XML is where you see it. The same sheet saved by openpyxl stores text as ",[14,1064,1065],{},"t=\"inlineStr\""," inside each cell, has no ",[14,1068,195],{}," at all, and writes formulas with an empty ",[14,1071,1033],{},":",[49,1074,1076],{"className":51,"code":1075,"language":53,"meta":54,"style":54},"from openpyxl import load_workbook\n\nload_workbook(\"orders.xlsx\").save(\"orders_openpyxl.xlsx\")\nzo = zipfile.ZipFile(\"orders_openpyxl.xlsx\")\nprint(\"sharedStrings.xml present:\", \"xl\u002FsharedStrings.xml\" in zo.namelist())\ncells = {c.get(\"r\"): c for c in ET.fromstring(zo.read(\"xl\u002Fworksheets\u002Fsheet1.xml\")).iter(f\"{{{NS['m']}}}c\")}\nprint(\"A2:\", cells[\"A2\"].get(\"t\"), \"| D2 cached value:\", repr(cells[\"D2\"].find(\"m:v\", NS).text))\n",[14,1077,1078,1091,1095,1110,1123,1143,1196],{"__ignoreMap":54},[58,1079,1080,1083,1086,1088],{"class":60,"line":61},[58,1081,1082],{"class":64},"from",[58,1084,1085],{"class":68}," openpyxl ",[58,1087,65],{"class":64},[58,1089,1090],{"class":68}," load_workbook\n",[58,1092,1093],{"class":60,"line":72},[58,1094,76],{"emptyLinePlaceholder":75},[58,1096,1097,1100,1102,1105,1108],{"class":60,"line":79},[58,1098,1099],{"class":68},"load_workbook(",[58,1101,92],{"class":91},[58,1103,1104],{"class":68},").save(",[58,1106,1107],{"class":91},"\"orders_openpyxl.xlsx\"",[58,1109,95],{"class":68},[58,1111,1112,1115,1117,1119,1121],{"class":60,"line":98},[58,1113,1114],{"class":68},"zo ",[58,1116,85],{"class":64},[58,1118,88],{"class":68},[58,1120,1107],{"class":91},[58,1122,95],{"class":68},[58,1124,1125,1127,1129,1132,1134,1137,1140],{"class":60,"line":113},[58,1126,718],{"class":116},[58,1128,120],{"class":68},[58,1130,1131],{"class":91},"\"sharedStrings.xml present:\"",[58,1133,200],{"class":68},[58,1135,1136],{"class":91},"\"xl\u002FsharedStrings.xml\"",[58,1138,1139],{"class":64}," in",[58,1141,1142],{"class":68}," zo.namelist())\n",[58,1144,1145,1148,1150,1153,1156,1159,1161,1163,1165,1167,1170,1173,1176,1178,1180,1182,1184,1186,1188,1190,1192,1194],{"class":60,"line":455},[58,1146,1147],{"class":68},"cells ",[58,1149,85],{"class":64},[58,1151,1152],{"class":68}," {c.get(",[58,1154,1155],{"class":91},"\"r\"",[58,1157,1158],{"class":68},"): c ",[58,1160,101],{"class":64},[58,1162,777],{"class":68},[58,1164,107],{"class":64},[58,1166,500],{"class":116},[58,1168,1169],{"class":68},".fromstring(zo.read(",[58,1171,1172],{"class":91},"\"xl\u002Fworksheets\u002Fsheet1.xml\"",[58,1174,1175],{"class":68},")).iter(",[58,1177,123],{"class":64},[58,1179,126],{"class":91},[58,1181,622],{"class":129},[58,1183,420],{"class":116},[58,1185,627],{"class":68},[58,1187,795],{"class":91},[58,1189,633],{"class":68},[58,1191,636],{"class":129},[58,1193,802],{"class":91},[58,1195,569],{"class":68},[58,1197,1198,1200,1202,1205,1208,1211,1214,1217,1220,1223,1225,1228,1231,1234,1237,1239,1241,1243],{"class":60,"line":468},[58,1199,718],{"class":116},[58,1201,120],{"class":68},[58,1203,1204],{"class":91},"\"A2:\"",[58,1206,1207],{"class":68},", cells[",[58,1209,1210],{"class":91},"\"A2\"",[58,1212,1213],{"class":68},"].get(",[58,1215,1216],{"class":91},"\"t\"",[58,1218,1219],{"class":68},"), ",[58,1221,1222],{"class":91},"\"| D2 cached value:\"",[58,1224,200],{"class":68},[58,1226,1227],{"class":116},"repr",[58,1229,1230],{"class":68},"(cells[",[58,1232,1233],{"class":91},"\"D2\"",[58,1235,1236],{"class":68},"].find(",[58,1238,827],{"class":91},[58,1240,200],{"class":68},[58,1242,420],{"class":116},[58,1244,1245],{"class":68},").text))\n",[10,1247,1248,1249,1251,1252,1255,1256,1259,1260,1263,1264,23],{},"That empty ",[14,1250,1033],{}," is why ",[14,1253,1254],{},"data_only=True"," and pandas read formula cells from openpyxl-written files as ",[14,1257,1258],{},"None"," or ",[14,1261,1262],{},"NaN",", while XlsxWriter files read as ",[14,1265,234],{},[212,1267,221,1273,221,1276,221,1279,221,1284,221,1291,221,1296,221,1304,221,1307,221,1368,221,1372,221,1376,221,1378,221,1441,221,1445,221,1495,221,1498,221,1502,221,1504,221,1554,221,1560,221,1564,221,1567,221,1572,221,1576,221,1579,221,1582,221,1584,221,1588,221,1591,221,1594,221,1597,221,1599,221,1603],{"viewBox":1268,"role":215,"ariaLabelledBy":1269,"xmlns":219,"style":1272},"4 0 752 206",[1270,1271],"xml-cells-t","xml-cells-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[223,1274,1275],{"id":1270},"Two cells as they appear in sheet1.xml",[227,1277,1278],{"id":1271},"The XML for four cells. A2 is a shared-string index, D2 a formula with a placeholder cached value of 0, E2 a boolean and F2 a date stored as the serial number 46266 with style index 2.",[231,1280],{"x":1281,"y":234,"width":1282,"height":1283,"fill":237},"4","752","206",[231,1285],{"x":1286,"y":241,"width":1287,"height":1288,"rx":244,"fill":1289,"stroke":246,"style":1290},"20.0","720.0","108.0","#f0f2f5","stroke-width:1.5px",[260,1292,1014],{"x":1293,"y":1294,"style":1295},"60.0","47.0","font-size:11px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace",[1297,1298],"circle",{"cx":1299,"cy":1300,"r":1301,"fill":1302,"stroke":256,"style":1303},"36.0","42.5","11.0","#4338ca","stroke-width:0px",[260,1305,1014],{"x":1299,"y":1294,"style":1306},"font-size:12px;font-weight:700;fill:#ffffff;text-anchor:middle",[260,1308,1311,1316,1319,1322,1324,1326,1329,1331,1333,1335,1338,1341,1343,1346,1348,1352,1354,1356,1358,1360,1362,1364,1366],{"x":1309,"y":1294,"style":1310},"82.0","font-size:12.5px;text-anchor:start;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace",[1312,1313,1315],"tspan",{"style":1314},"fill:var(--text,#172033);font-weight:400","\u003C",[1312,1317,1318],{"style":1314},"c",[1312,1320,1321],{"style":1314}," ",[1312,1323,983],{"style":1314},[1312,1325,85],{"style":1314},[1312,1327,1210],{"style":1328},"fill:var(--teal-ink,#0b6157);font-weight:400",[1312,1330,1321],{"style":1314},[1312,1332,991],{"style":1314},[1312,1334,85],{"style":1314},[1312,1336,1337],{"style":1328},"\"s\"",[1312,1339,1340],{"style":1314},">",[1312,1342,1315],{"style":1314},[1312,1344,1345],{"style":1314},"v",[1312,1347,1340],{"style":1314},[1312,1349,1351],{"style":1350},"fill:var(--gold-ink,#7a4e06);font-weight:400","6",[1312,1353,1315],{"style":1314},[1312,1355,1015],{"style":1314},[1312,1357,1345],{"style":1314},[1312,1359,1340],{"style":1314},[1312,1361,1315],{"style":1314},[1312,1363,1015],{"style":1314},[1312,1365,1318],{"style":1314},[1312,1367,1340],{"style":1314},[260,1369,1371],{"x":1293,"y":1370,"style":1295},"68.0","2",[1297,1373],{"cx":1299,"cy":1374,"r":1301,"fill":1375,"stroke":256,"style":1303},"63.5","#8a5808",[260,1377,1371],{"x":1299,"y":1370,"style":1306},[260,1379,1380,1382,1384,1386,1388,1390,1392,1394,1396,1398,1400,1403,1406,1409,1411,1413,1415,1417,1419,1421,1423,1425,1427,1429,1431,1433,1435,1437,1439],{"x":1309,"y":1370,"style":1310},[1312,1381,1315],{"style":1314},[1312,1383,1318],{"style":1314},[1312,1385,1321],{"style":1314},[1312,1387,983],{"style":1314},[1312,1389,85],{"style":1314},[1312,1391,1233],{"style":1328},[1312,1393,1340],{"style":1314},[1312,1395,1315],{"style":1314},[1312,1397,123],{"style":1314},[1312,1399,1340],{"style":1314},[1312,1401,1402],{"style":1314},"B2",[1312,1404,1405],{"style":1314},"*",[1312,1407,1408],{"style":1314},"C2",[1312,1410,1315],{"style":1314},[1312,1412,1015],{"style":1314},[1312,1414,123],{"style":1314},[1312,1416,1340],{"style":1314},[1312,1418,1315],{"style":1314},[1312,1420,1345],{"style":1314},[1312,1422,1340],{"style":1314},[1312,1424,234],{"style":1350},[1312,1426,1315],{"style":1314},[1312,1428,1015],{"style":1314},[1312,1430,1345],{"style":1314},[1312,1432,1340],{"style":1314},[1312,1434,1315],{"style":1314},[1312,1436,1015],{"style":1314},[1312,1438,1318],{"style":1314},[1312,1440,1340],{"style":1314},[260,1442,1444],{"x":1293,"y":1443,"style":1295},"89.0","3",[260,1446,1447,1449,1451,1453,1455,1457,1460,1462,1464,1466,1469,1471,1473,1475,1477,1479,1481,1483,1485,1487,1489,1491,1493],{"x":1309,"y":1443,"style":1310},[1312,1448,1315],{"style":1314},[1312,1450,1318],{"style":1314},[1312,1452,1321],{"style":1314},[1312,1454,983],{"style":1314},[1312,1456,85],{"style":1314},[1312,1458,1459],{"style":1328},"\"E2\"",[1312,1461,1321],{"style":1314},[1312,1463,991],{"style":1314},[1312,1465,85],{"style":1314},[1312,1467,1468],{"style":1328},"\"b\"",[1312,1470,1340],{"style":1314},[1312,1472,1315],{"style":1314},[1312,1474,1345],{"style":1314},[1312,1476,1340],{"style":1314},[1312,1478,1014],{"style":1350},[1312,1480,1315],{"style":1314},[1312,1482,1015],{"style":1314},[1312,1484,1345],{"style":1314},[1312,1486,1340],{"style":1314},[1312,1488,1315],{"style":1314},[1312,1490,1015],{"style":1314},[1312,1492,1318],{"style":1314},[1312,1494,1340],{"style":1314},[260,1496,1281],{"x":1293,"y":1497,"style":1295},"110.0",[1297,1499],{"cx":1299,"cy":1500,"r":1301,"fill":1501,"stroke":256,"style":1303},"105.5","#0b6157",[260,1503,1444],{"x":1299,"y":1497,"style":1306},[260,1505,1506,1508,1510,1512,1514,1516,1519,1521,1523,1525,1528,1530,1532,1534,1536,1538,1540,1542,1544,1546,1548,1550,1552],{"x":1309,"y":1497,"style":1310},[1312,1507,1315],{"style":1314},[1312,1509,1318],{"style":1314},[1312,1511,1321],{"style":1314},[1312,1513,983],{"style":1314},[1312,1515,85],{"style":1314},[1312,1517,1518],{"style":1328},"\"F2\"",[1312,1520,1321],{"style":1314},[1312,1522,987],{"style":1314},[1312,1524,85],{"style":1314},[1312,1526,1527],{"style":1328},"\"2\"",[1312,1529,1340],{"style":1314},[1312,1531,1315],{"style":1314},[1312,1533,1345],{"style":1314},[1312,1535,1340],{"style":1314},[1312,1537,1041],{"style":1350},[1312,1539,1315],{"style":1314},[1312,1541,1015],{"style":1314},[1312,1543,1345],{"style":1314},[1312,1545,1340],{"style":1314},[1312,1547,1315],{"style":1314},[1312,1549,1015],{"style":1314},[1312,1551,1318],{"style":1314},[1312,1553,1340],{"style":1314},[231,1555],{"x":1286,"y":1556,"width":1557,"height":1558,"rx":1559,"fill":284,"stroke":275,"style":1290},"138.0","230.7","52.0","10",[1297,1561],{"cx":1562,"cy":1563,"r":1301,"fill":1302,"stroke":256,"style":1303},"40.0","164.0",[260,1565,1014],{"x":1562,"y":1566,"style":1306},"168.5",[260,1568,1571],{"x":1293,"y":1569,"style":1570},"160.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","t=\"s\": text is entry 6 of",[260,1573,1575],{"x":1293,"y":1574,"style":1570},"177.0","sharedStrings",[231,1577],{"x":1578,"y":1556,"width":1557,"height":1558,"rx":1559,"fill":361,"stroke":362,"style":1290},"264.7",[1297,1580],{"cx":1581,"cy":1563,"r":1301,"fill":1375,"stroke":256,"style":1303},"284.7",[260,1583,1371],{"x":1581,"y":1566,"style":1306},[260,1585,1587],{"x":1586,"y":1569,"style":1570},"304.7","\u003Cf> formula with a",[260,1589,1590],{"x":1586,"y":1574,"style":1570},"placeholder cached 0",[231,1592],{"x":1593,"y":1556,"width":1557,"height":1558,"rx":1559,"fill":334,"stroke":335,"style":1290},"509.3",[1297,1595],{"cx":1596,"cy":1563,"r":1301,"fill":1501,"stroke":256,"style":1303},"529.3",[260,1598,1444],{"x":1596,"y":1566,"style":1306},[260,1600,1602],{"x":1601,"y":1569,"style":1570},"549.3","a date is a number; s=2 gives",[260,1604,1605],{"x":1601,"y":1574,"style":1570},"its format",[25,1607,1609],{"id":1608},"step-4-resolve-shared-strings-and-number-formats","Step 4 — Resolve shared strings and number formats",[10,1611,1612,1613,1615,1616,1618,1619,1621,1622,1625,1626,1629,1630,1633,1634,1072],{},"Text cells with ",[14,1614,1037],{}," store an index; the text is in ",[14,1617,195],{},". Formats are two hops away: the cell's ",[14,1620,987],{}," indexes the ",[14,1623,1624],{},"cellXfs"," list in ",[14,1627,1628],{},"styles.xml",", whose ",[14,1631,1632],{},"numFmtId"," either names a built-in format or one defined in ",[14,1635,1636],{},"numFmts",[49,1638,1640],{"className":51,"code":1639,"language":53,"meta":54,"style":54},"def shared_strings(z):\n    if \"xl\u002FsharedStrings.xml\" not in z.namelist():\n        return []\n    root = ET.fromstring(z.read(\"xl\u002FsharedStrings.xml\"))\n    return [\"\".join(t.text or \"\" for t in si.iter(f\"{{{NS['m']}}}t\")) for si in root.findall(\"m:si\", NS)]\n\ndef number_formats(z):\n    styles = ET.fromstring(z.read(\"xl\u002Fstyles.xml\"))\n    custom = {n.get(\"numFmtId\"): n.get(\"formatCode\") for n in styles.iterfind(\"m:numFmts\u002Fm:numFmt\", NS)}\n    builtin = {\"0\": \"General\", \"14\": \"mm-dd-yy\", \"22\": \"m\u002Fd\u002Fyy h:mm\"}\n    return [custom.get(x.get(\"numFmtId\"), builtin.get(x.get(\"numFmtId\"), \"built-in \" + x.get(\"numFmtId\")))\n            for x in styles.iterfind(\"m:cellXfs\u002Fm:xf\", NS)]\n\nstrings, fmts = shared_strings(z), number_formats(z)\nprint(\"shared strings:\", strings)\nfor c in sheet.iter(f\"{{{NS['m']}}}c\"):\n    if c.get(\"r\") in (\"A2\", \"C2\", \"F2\"):\n        v = c.find(\"m:v\", NS).text\n        shown = strings[int(v)] if c.get(\"t\") == \"s\" else v\n        print(c.get(\"r\"), repr(shown), \"format:\", fmts[int(c.get(\"s\", 0))])\n",[14,1641,1642,1651,1666,1674,1689,1761,1765,1774,1790,1830,1869,1898,1919,1923,1933,1945,1975,2003,2021,2056],{"__ignoreMap":54},[58,1643,1644,1646,1649],{"class":60,"line":61},[58,1645,482],{"class":64},[58,1647,1648],{"class":485}," shared_strings",[58,1650,489],{"class":68},[58,1652,1653,1656,1659,1661,1663],{"class":60,"line":72},[58,1654,1655],{"class":64},"    if",[58,1657,1658],{"class":91}," \"xl\u002FsharedStrings.xml\"",[58,1660,928],{"class":64},[58,1662,1139],{"class":64},[58,1664,1665],{"class":68}," z.namelist():\n",[58,1667,1668,1671],{"class":60,"line":79},[58,1669,1670],{"class":64},"        return",[58,1672,1673],{"class":68}," []\n",[58,1675,1676,1679,1681,1683,1685,1687],{"class":60,"line":98},[58,1677,1678],{"class":68},"    root ",[58,1680,85],{"class":64},[58,1682,500],{"class":116},[58,1684,503],{"class":68},[58,1686,1136],{"class":91},[58,1688,509],{"class":68},[58,1690,1691,1693,1696,1699,1702,1705,1708,1711,1714,1716,1719,1721,1723,1725,1727,1729,1731,1733,1735,1738,1741,1743,1746,1748,1751,1754,1756,1758],{"class":60,"line":113},[58,1692,693],{"class":64},[58,1694,1695],{"class":68}," [",[58,1697,1698],{"class":91},"\"\"",[58,1700,1701],{"class":68},".join(t.text ",[58,1703,1704],{"class":64},"or",[58,1706,1707],{"class":91}," \"\"",[58,1709,1710],{"class":64}," for",[58,1712,1713],{"class":68}," t ",[58,1715,107],{"class":64},[58,1717,1718],{"class":68}," si.iter(",[58,1720,123],{"class":64},[58,1722,126],{"class":91},[58,1724,622],{"class":129},[58,1726,420],{"class":116},[58,1728,627],{"class":68},[58,1730,795],{"class":91},[58,1732,633],{"class":68},[58,1734,636],{"class":129},[58,1736,1737],{"class":91},"t\"",[58,1739,1740],{"class":68},")) ",[58,1742,101],{"class":64},[58,1744,1745],{"class":68}," si ",[58,1747,107],{"class":64},[58,1749,1750],{"class":68}," root.findall(",[58,1752,1753],{"class":91},"\"m:si\"",[58,1755,200],{"class":68},[58,1757,420],{"class":116},[58,1759,1760],{"class":68},")]\n",[58,1762,1763],{"class":60,"line":455},[58,1764,76],{"emptyLinePlaceholder":75},[58,1766,1767,1769,1772],{"class":60,"line":468},[58,1768,482],{"class":64},[58,1770,1771],{"class":485}," number_formats",[58,1773,489],{"class":68},[58,1775,1776,1779,1781,1783,1785,1788],{"class":60,"line":474},[58,1777,1778],{"class":68},"    styles ",[58,1780,85],{"class":64},[58,1782,500],{"class":116},[58,1784,503],{"class":68},[58,1786,1787],{"class":91},"\"xl\u002Fstyles.xml\"",[58,1789,509],{"class":68},[58,1791,1792,1795,1797,1800,1803,1806,1809,1811,1813,1816,1818,1821,1824,1826,1828],{"class":60,"line":479},[58,1793,1794],{"class":68},"    custom ",[58,1796,85],{"class":64},[58,1798,1799],{"class":68}," {n.get(",[58,1801,1802],{"class":91},"\"numFmtId\"",[58,1804,1805],{"class":68},"): n.get(",[58,1807,1808],{"class":91},"\"formatCode\"",[58,1810,549],{"class":68},[58,1812,101],{"class":64},[58,1814,1815],{"class":68}," n ",[58,1817,107],{"class":64},[58,1819,1820],{"class":68}," styles.iterfind(",[58,1822,1823],{"class":91},"\"m:numFmts\u002Fm:numFmt\"",[58,1825,200],{"class":68},[58,1827,420],{"class":116},[58,1829,569],{"class":68},[58,1831,1832,1835,1837,1839,1842,1844,1847,1849,1852,1854,1857,1859,1862,1864,1867],{"class":60,"line":492},[58,1833,1834],{"class":68},"    builtin ",[58,1836,85],{"class":64},[58,1838,142],{"class":68},[58,1840,1841],{"class":91},"\"0\"",[58,1843,434],{"class":68},[58,1845,1846],{"class":91},"\"General\"",[58,1848,200],{"class":68},[58,1850,1851],{"class":91},"\"14\"",[58,1853,434],{"class":68},[58,1855,1856],{"class":91},"\"mm-dd-yy\"",[58,1858,200],{"class":68},[58,1860,1861],{"class":91},"\"22\"",[58,1863,434],{"class":68},[58,1865,1866],{"class":91},"\"m\u002Fd\u002Fyy h:mm\"",[58,1868,471],{"class":68},[58,1870,1871,1873,1876,1878,1881,1883,1885,1888,1890,1893,1895],{"class":60,"line":512},[58,1872,693],{"class":64},[58,1874,1875],{"class":68}," [custom.get(x.get(",[58,1877,1802],{"class":91},[58,1879,1880],{"class":68},"), builtin.get(x.get(",[58,1882,1802],{"class":91},[58,1884,1219],{"class":68},[58,1886,1887],{"class":91},"\"built-in \"",[58,1889,684],{"class":64},[58,1891,1892],{"class":68}," x.get(",[58,1894,1802],{"class":91},[58,1896,1897],{"class":68},")))\n",[58,1899,1900,1903,1906,1908,1910,1913,1915,1917],{"class":60,"line":529},[58,1901,1902],{"class":64},"            for",[58,1904,1905],{"class":68}," x ",[58,1907,107],{"class":64},[58,1909,1820],{"class":68},[58,1911,1912],{"class":91},"\"m:cellXfs\u002Fm:xf\"",[58,1914,200],{"class":68},[58,1916,420],{"class":116},[58,1918,1760],{"class":68},[58,1920,1921],{"class":60,"line":572},[58,1922,76],{"emptyLinePlaceholder":75},[58,1924,1925,1928,1930],{"class":60,"line":583},[58,1926,1927],{"class":68},"strings, fmts ",[58,1929,85],{"class":64},[58,1931,1932],{"class":68}," shared_strings(z), number_formats(z)\n",[58,1934,1935,1937,1939,1942],{"class":60,"line":607},[58,1936,718],{"class":116},[58,1938,120],{"class":68},[58,1940,1941],{"class":91},"\"shared strings:\"",[58,1943,1944],{"class":68},", strings)\n",[58,1946,1947,1949,1951,1953,1955,1957,1959,1961,1963,1965,1967,1969,1971,1973],{"class":60,"line":650},[58,1948,101],{"class":64},[58,1950,777],{"class":68},[58,1952,107],{"class":64},[58,1954,782],{"class":68},[58,1956,123],{"class":64},[58,1958,126],{"class":91},[58,1960,622],{"class":129},[58,1962,420],{"class":116},[58,1964,627],{"class":68},[58,1966,795],{"class":91},[58,1968,633],{"class":68},[58,1970,636],{"class":129},[58,1972,802],{"class":91},[58,1974,604],{"class":68},[58,1976,1977,1979,1982,1984,1986,1988,1990,1992,1994,1997,1999,2001],{"class":60,"line":690},[58,1978,1655],{"class":64},[58,1980,1981],{"class":68}," c.get(",[58,1983,1155],{"class":91},[58,1985,549],{"class":68},[58,1987,107],{"class":64},[58,1989,731],{"class":68},[58,1991,1210],{"class":91},[58,1993,200],{"class":68},[58,1995,1996],{"class":91},"\"C2\"",[58,1998,200],{"class":68},[58,2000,1518],{"class":91},[58,2002,604],{"class":68},[58,2004,2005,2008,2010,2012,2014,2016,2018],{"class":60,"line":699},[58,2006,2007],{"class":68},"        v ",[58,2009,85],{"class":64},[58,2011,814],{"class":68},[58,2013,827],{"class":91},[58,2015,200],{"class":68},[58,2017,420],{"class":116},[58,2019,2020],{"class":68},").text\n",[58,2022,2023,2026,2028,2031,2034,2037,2039,2041,2043,2045,2048,2051,2053],{"class":60,"line":704},[58,2024,2025],{"class":68},"        shown ",[58,2027,85],{"class":64},[58,2029,2030],{"class":68}," strings[",[58,2032,2033],{"class":116},"int",[58,2035,2036],{"class":68},"(v)] ",[58,2038,667],{"class":64},[58,2040,1981],{"class":68},[58,2042,1216],{"class":91},[58,2044,549],{"class":68},[58,2046,2047],{"class":64},"==",[58,2049,2050],{"class":91}," \"s\"",[58,2052,934],{"class":64},[58,2054,2055],{"class":68}," v\n",[58,2057,2058,2061,2064,2066,2068,2070,2073,2076,2079,2081,2083,2085,2087,2089],{"class":60,"line":715},[58,2059,2060],{"class":116},"        print",[58,2062,2063],{"class":68},"(c.get(",[58,2065,1155],{"class":91},[58,2067,1219],{"class":68},[58,2069,1227],{"class":116},[58,2071,2072],{"class":68},"(shown), ",[58,2074,2075],{"class":91},"\"format:\"",[58,2077,2078],{"class":68},", fmts[",[58,2080,2033],{"class":116},[58,2082,2063],{"class":68},[58,2084,1337],{"class":91},[58,2086,200],{"class":68},[58,2088,234],{"class":116},[58,2090,2091],{"class":68},"))])\n",[10,2093,2094,2095,2098,2099,2102,2103,2106,2107,2110,2111,2115],{},"Joining every ",[14,2096,2097],{},"\u003Ct>"," inside an ",[14,2100,2101],{},"\u003Csi>"," handles rich-text strings, which split one cell's text into several runs. The number-format lookup shows ",[14,2104,2105],{},"#,##0.00 [$EUR]"," on the price and ",[14,2108,2109],{},"dd mmm yyyy"," on the date — exactly what ",[19,2112,2114],{"href":2113},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel\u002Fread-cell-values-as-displayed-in-excel\u002F","Read Cell Values as Displayed in Excel"," needs to reproduce the on-screen text.",[25,2117,2119],{"id":2118},"step-5-pretty-print-a-part","Step 5 — Pretty-print a part",[10,2121,2122],{},"Writers save XML on one long line. Indenting it makes it readable in a terminal or a diff:",[49,2124,2126],{"className":51,"code":2125,"language":53,"meta":54,"style":54},"import xml.dom.minidom\n\ndef pretty(z, part, limit=900):\n    return xml.dom.minidom.parseString(z.read(part)).toprettyxml(indent=\"  \")[:limit]\n\nprint(pretty(z, \"xl\u002Fworksheets\u002Fsheet1.xml\", 700))\nfor f in (\"orders.xlsx\", \"orders_openpyxl.xlsx\"):\n    app = ET.fromstring(zipfile.ZipFile(f).read(\"docProps\u002Fapp.xml\"))\n    print(f, \"->\", app.find(\"{http:\u002F\u002Fschemas.openxmlformats.org\u002FofficeDocument\u002F2006\u002Fextended-properties}Application\").text)\n",[14,2127,2128,2135,2139,2156,2175,2179,2195,2213,2230],{"__ignoreMap":54},[58,2129,2130,2132],{"class":60,"line":61},[58,2131,65],{"class":64},[58,2133,2134],{"class":68}," xml.dom.minidom\n",[58,2136,2137],{"class":60,"line":72},[58,2138,76],{"emptyLinePlaceholder":75},[58,2140,2141,2143,2146,2149,2151,2154],{"class":60,"line":79},[58,2142,482],{"class":64},[58,2144,2145],{"class":485}," pretty",[58,2147,2148],{"class":68},"(z, part, limit",[58,2150,85],{"class":64},[58,2152,2153],{"class":116},"900",[58,2155,604],{"class":68},[58,2157,2158,2160,2163,2167,2169,2172],{"class":60,"line":98},[58,2159,693],{"class":64},[58,2161,2162],{"class":68}," xml.dom.minidom.parseString(z.read(part)).toprettyxml(",[58,2164,2166],{"class":2165},"sa561","indent",[58,2168,85],{"class":64},[58,2170,2171],{"class":91},"\"  \"",[58,2173,2174],{"class":68},")[:limit]\n",[58,2176,2177],{"class":60,"line":113},[58,2178,76],{"emptyLinePlaceholder":75},[58,2180,2181,2183,2186,2188,2190,2193],{"class":60,"line":455},[58,2182,718],{"class":116},[58,2184,2185],{"class":68},"(pretty(z, ",[58,2187,1172],{"class":91},[58,2189,200],{"class":68},[58,2191,2192],{"class":116},"700",[58,2194,509],{"class":68},[58,2196,2197,2199,2201,2203,2205,2207,2209,2211],{"class":60,"line":468},[58,2198,101],{"class":64},[58,2200,922],{"class":68},[58,2202,107],{"class":64},[58,2204,731],{"class":68},[58,2206,92],{"class":91},[58,2208,200],{"class":68},[58,2210,1107],{"class":91},[58,2212,604],{"class":68},[58,2214,2215,2218,2220,2222,2225,2228],{"class":60,"line":474},[58,2216,2217],{"class":68},"    app ",[58,2219,85],{"class":64},[58,2221,500],{"class":116},[58,2223,2224],{"class":68},".fromstring(zipfile.ZipFile(f).read(",[58,2226,2227],{"class":91},"\"docProps\u002Fapp.xml\"",[58,2229,509],{"class":68},[58,2231,2232,2234,2237,2240,2243,2245,2248,2250,2253,2256],{"class":60,"line":479},[58,2233,117],{"class":116},[58,2235,2236],{"class":68},"(f, ",[58,2238,2239],{"class":91},"\"->\"",[58,2241,2242],{"class":68},", app.find(",[58,2244,126],{"class":91},[58,2246,2247],{"class":129},"{http",[58,2249,1072],{"class":64},[58,2251,2252],{"class":129},"\u002F\u002Fschemas.openxmlformats.org\u002FofficeDocument\u002F2006\u002Fextended-properties}",[58,2254,2255],{"class":91},"Application\"",[58,2257,2258],{"class":68},").text)\n",[10,2260,2261,2263,2264,2267,2268,2271,2272,2275,2276,2279],{},[14,2262,188],{}," has an ",[14,2265,2266],{},"Application"," element, but treat it as a hint rather than proof: XlsxWriter writes ",[14,2269,2270],{},"Microsoft Excel"," there, so its files claim to come from Excel, while openpyxl writes ",[14,2273,2274],{},"Microsoft Excel Compatible \u002F Openpyxl 3.1.5",". The structure of the parts is a better fingerprint — inline strings and empty cached values point to openpyxl, a shared-string table with cached zeros to XlsxWriter, and a ",[14,2277,2278],{},"calcChain.xml"," part to a workbook that Excel itself has calculated and saved. For large sheet parts, print a slice; a sheet with 100,000 rows is many megabytes of XML.",[25,2281,2283],{"id":2282},"step-6-diff-two-workbooks-part-by-part","Step 6 — Diff two workbooks part by part",[10,2285,2286],{},"When a tool \"changes nothing\" but the file looks different, compare the packages. The re-save from Step 3 is a good example — same data, different writer:",[49,2288,2290],{"className":51,"code":2289,"language":53,"meta":54,"style":54},"import difflib\n\ndef diff_packages(path_a, path_b):\n    a, b = zipfile.ZipFile(path_a), zipfile.ZipFile(path_b)\n    print(\"only in\", path_a, sorted(set(a.namelist()) - set(b.namelist())))\n    print(\"only in\", path_b, sorted(set(b.namelist()) - set(a.namelist())))\n    for part in sorted(set(a.namelist()) & set(b.namelist())):\n        if part.endswith(\".xml\") and a.read(part) != b.read(part):\n            left, right = pretty(a, part, 10**7).splitlines(), pretty(b, part, 10**7).splitlines()\n            changed = sum(1 for l in difflib.unified_diff(left, right, lineterm=\"\", n=0)\n                          if l[:1] in \"+-\" and l[:3] not in (\"+++\", \"---\"))\n            print(f\"  {part:28} {changed} changed lines\")\n\ndiff_packages(\"orders.xlsx\", \"orders_openpyxl.xlsx\")\n",[14,2291,2292,2299,2303,2313,2323,2355,2382,2408,2433,2463,2504,2548,2582,2586],{"__ignoreMap":54},[58,2293,2294,2296],{"class":60,"line":61},[58,2295,65],{"class":64},[58,2297,2298],{"class":68}," difflib\n",[58,2300,2301],{"class":60,"line":72},[58,2302,76],{"emptyLinePlaceholder":75},[58,2304,2305,2307,2310],{"class":60,"line":79},[58,2306,482],{"class":64},[58,2308,2309],{"class":485}," diff_packages",[58,2311,2312],{"class":68},"(path_a, path_b):\n",[58,2314,2315,2318,2320],{"class":60,"line":98},[58,2316,2317],{"class":68},"    a, b ",[58,2319,85],{"class":64},[58,2321,2322],{"class":68}," zipfile.ZipFile(path_a), zipfile.ZipFile(path_b)\n",[58,2324,2325,2327,2329,2332,2335,2338,2340,2343,2346,2349,2352],{"class":60,"line":113},[58,2326,117],{"class":116},[58,2328,120],{"class":68},[58,2330,2331],{"class":91},"\"only in\"",[58,2333,2334],{"class":68},", path_a, ",[58,2336,2337],{"class":116},"sorted",[58,2339,120],{"class":68},[58,2341,2342],{"class":116},"set",[58,2344,2345],{"class":68},"(a.namelist()) ",[58,2347,2348],{"class":64},"-",[58,2350,2351],{"class":116}," set",[58,2353,2354],{"class":68},"(b.namelist())))\n",[58,2356,2357,2359,2361,2363,2366,2368,2370,2372,2375,2377,2379],{"class":60,"line":455},[58,2358,117],{"class":116},[58,2360,120],{"class":68},[58,2362,2331],{"class":91},[58,2364,2365],{"class":68},", path_b, ",[58,2367,2337],{"class":116},[58,2369,120],{"class":68},[58,2371,2342],{"class":116},[58,2373,2374],{"class":68},"(b.namelist()) ",[58,2376,2348],{"class":64},[58,2378,2351],{"class":116},[58,2380,2381],{"class":68},"(a.namelist())))\n",[58,2383,2384,2386,2389,2391,2394,2396,2398,2400,2403,2405],{"class":60,"line":468},[58,2385,586],{"class":64},[58,2387,2388],{"class":68}," part ",[58,2390,107],{"class":64},[58,2392,2393],{"class":116}," sorted",[58,2395,120],{"class":68},[58,2397,2342],{"class":116},[58,2399,2345],{"class":68},[58,2401,2402],{"class":64},"&",[58,2404,2351],{"class":116},[58,2406,2407],{"class":68},"(b.namelist())):\n",[58,2409,2410,2413,2416,2419,2421,2424,2427,2430],{"class":60,"line":474},[58,2411,2412],{"class":64},"        if",[58,2414,2415],{"class":68}," part.endswith(",[58,2417,2418],{"class":91},"\".xml\"",[58,2420,549],{"class":68},[58,2422,2423],{"class":64},"and",[58,2425,2426],{"class":68}," a.read(part) ",[58,2428,2429],{"class":64},"!=",[58,2431,2432],{"class":68}," b.read(part):\n",[58,2434,2435,2438,2440,2443,2445,2448,2451,2454,2456,2458,2460],{"class":60,"line":479},[58,2436,2437],{"class":68},"            left, right ",[58,2439,85],{"class":64},[58,2441,2442],{"class":68}," pretty(a, part, ",[58,2444,1559],{"class":116},[58,2446,2447],{"class":64},"**",[58,2449,2450],{"class":116},"7",[58,2452,2453],{"class":68},").splitlines(), pretty(b, part, ",[58,2455,1559],{"class":116},[58,2457,2447],{"class":64},[58,2459,2450],{"class":116},[58,2461,2462],{"class":68},").splitlines()\n",[58,2464,2465,2468,2470,2473,2475,2477,2479,2482,2484,2487,2490,2492,2494,2496,2498,2500,2502],{"class":60,"line":492},[58,2466,2467],{"class":68},"            changed ",[58,2469,85],{"class":64},[58,2471,2472],{"class":116}," sum",[58,2474,120],{"class":68},[58,2476,1014],{"class":116},[58,2478,1710],{"class":64},[58,2480,2481],{"class":68}," l ",[58,2483,107],{"class":64},[58,2485,2486],{"class":68}," difflib.unified_diff(left, right, ",[58,2488,2489],{"class":2165},"lineterm",[58,2491,85],{"class":64},[58,2493,1698],{"class":91},[58,2495,200],{"class":68},[58,2497,995],{"class":2165},[58,2499,85],{"class":64},[58,2501,234],{"class":116},[58,2503,95],{"class":68},[58,2505,2506,2509,2512,2514,2517,2519,2522,2525,2527,2529,2531,2534,2536,2538,2541,2543,2546],{"class":60,"line":512},[58,2507,2508],{"class":64},"                          if",[58,2510,2511],{"class":68}," l[:",[58,2513,1014],{"class":116},[58,2515,2516],{"class":68},"] ",[58,2518,107],{"class":64},[58,2520,2521],{"class":91}," \"+-\"",[58,2523,2524],{"class":64}," and",[58,2526,2511],{"class":68},[58,2528,1444],{"class":116},[58,2530,2516],{"class":68},[58,2532,2533],{"class":64},"not",[58,2535,1139],{"class":64},[58,2537,731],{"class":68},[58,2539,2540],{"class":91},"\"+++\"",[58,2542,200],{"class":68},[58,2544,2545],{"class":91},"\"---\"",[58,2547,509],{"class":68},[58,2549,2550,2553,2555,2557,2560,2562,2565,2568,2570,2572,2575,2577,2580],{"class":60,"line":529},[58,2551,2552],{"class":116},"            print",[58,2554,120],{"class":68},[58,2556,123],{"class":64},[58,2558,2559],{"class":91},"\"  ",[58,2561,130],{"class":129},[58,2563,2564],{"class":68},"part",[58,2566,2567],{"class":64},":28",[58,2569,139],{"class":129},[58,2571,142],{"class":129},[58,2573,2574],{"class":68},"changed",[58,2576,139],{"class":129},[58,2578,2579],{"class":91}," changed lines\"",[58,2581,95],{"class":68},[58,2583,2584],{"class":60,"line":572},[58,2585,76],{"emptyLinePlaceholder":75},[58,2587,2588,2591,2593,2595,2597],{"class":60,"line":583},[58,2589,2590],{"class":68},"diff_packages(",[58,2592,92],{"class":91},[58,2594,200],{"class":68},[58,2596,1107],{"class":91},[58,2598,95],{"class":68},[10,2600,2601,2602,2606,2607,2611,2612,23],{},"The report lists the shared-strings part as present only in the original and counts changed lines per part. Between two different writers almost every part differs, because each orders attributes and styles its own way; the useful comparison is between two saves by the ",[2603,2604,2605],"em",{},"same"," tool — yesterday's and today's report, or a workbook before and after one script step — where only the parts that really changed show up. Print the diff lines themselves for those parts. On a workbook saved by Excel, the same comparison after an openpyxl round trip shows exactly what openpyxl drops or rewrites, the evidence behind ",[19,2608,2610],{"href":2609},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fwhat-openpyxl-loses-when-saving-an-existing-workbook\u002F","What openpyxl Loses When Saving an Existing Workbook",". For diffs in version control, the same idea powers ",[19,2613,2615],{"href":2614},"\u002Fautomating-reporting-workflows\u002Ftesting-and-packaging-excel-automation-scripts\u002Fdiff-excel-files-in-git-with-a-textconv-driver\u002F","Diff Excel Files in Git with a textconv Driver",[212,2617,221,2622,221,2625,221,2628,221,2631,221,2635,221,2640,221,2645,221,2649,221,2654,221,2657,221,2660,221,2666,221,2670,221,2673,221,2677,221,2680,221,2683,221,2689,221,2693,221,2695,221,2699,221,2703,221,2706,221,2709,221,2715,221,2719],{"viewBox":2618,"role":215,"ariaLabelledBy":2619,"xmlns":219,"style":1272},"4 0 752 142",[2620,2621],"xml-diff-t","xml-diff-d",[223,2623,2624],{"id":2620},"Diffing two workbooks part by part",[227,2626,2627],{"id":2621},"Both files are opened as ZIP archives, their part lists are compared for added and removed parts, each shared part is pretty-printed, and a line diff reports what changed.",[231,2629],{"x":1281,"y":234,"width":1282,"height":2630,"fill":237},"142",[231,2632],{"x":1286,"y":241,"width":2633,"height":2634,"rx":244,"fill":245,"stroke":246,"style":247},"153.0","110.5",[249,2636,2638],{"transform":2637},"translate(84.5,37.8) scale(1.000)",[253,2639],{"d":255,"fill":256,"stroke":257,"style":258},[260,2641,2644],{"x":2642,"y":2643,"style":264},"96.5","84.2","Open both as ZIPs",[260,2646,2648],{"x":2642,"y":2647,"style":269},"103.8","zipfile.ZipFile",[60,2650],{"x1":2651,"y1":2652,"x2":2653,"y2":2652,"stroke":275,"style":247},"178.0","71.2","200.0",[277,2655],{"points":2656,"fill":280},"204.0,71.2 195.0,76.2 195.0,66.2",[231,2658],{"x":2659,"y":241,"width":2633,"height":2634,"rx":244,"fill":284,"stroke":275,"style":247},"209.0",[249,2661,2663],{"transform":2662},"translate(273.5,37.8) scale(1.000)",[253,2664],{"d":2665,"fill":256,"stroke":291,"style":258},"M12 3l9 5-9 5-9-5z M3 13l9 5 9-5 M3 17l9 5 9-5",[260,2667,2669],{"x":2668,"y":2643,"style":295},"285.5","Compare part lists",[260,2671,2672],{"x":2668,"y":2647,"style":269},"added \u002F removed parts",[60,2674],{"x1":2675,"y1":2652,"x2":2676,"y2":2652,"stroke":275,"style":247},"367.0","389.0",[277,2678],{"points":2679,"fill":280},"393.0,71.2 384.0,76.2 384.0,66.2",[231,2681],{"x":2682,"y":241,"width":2633,"height":2634,"rx":244,"fill":284,"stroke":275,"style":247},"398.0",[249,2684,2686],{"transform":2685},"translate(462.5,29.0) scale(1.000)",[253,2687],{"d":2688,"fill":256,"stroke":291,"style":258},"M9 8l-4 4 4 4 M15 8l4 4-4 4",[260,2690,2692],{"x":2691,"y":263,"style":295},"474.5","Pretty-print each",[260,2694,2564],{"x":2691,"y":243,"style":295},[260,2696,2698],{"x":2691,"y":2697,"style":269},"112.5","minidom",[60,2700],{"x1":2701,"y1":2652,"x2":2702,"y2":2652,"stroke":275,"style":247},"556.0","578.0",[277,2704],{"points":2705,"fill":280},"582.0,71.2 573.0,76.2 573.0,66.2",[231,2707],{"x":2708,"y":241,"width":2633,"height":2634,"rx":244,"fill":334,"stroke":335,"style":247},"587.0",[249,2710,2712],{"transform":2711},"translate(651.5,37.8) scale(1.000)",[253,2713],{"d":2714,"fill":256,"stroke":342,"style":258},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5",[260,2716,2718],{"x":2717,"y":2643,"style":346},"663.5","Line diff",[260,2720,2721],{"x":2717,"y":2647,"style":269},"difflib.unified_diff",[25,2723,2725],{"id":2724},"common-pitfalls","Common pitfalls",[2727,2728,2729,2744,2753,2764,2770],"ul",{},[2730,2731,2732,1321,2736,2739,2740,2743],"li",{},[2733,2734,2735],"strong",{},"Forgetting namespaces.",[14,2737,2738],{},"root.find(\"sheets\")"," finds nothing; use the ",[14,2741,2742],{},"{namespace}tag"," form or a prefix map.",[2730,2745,2746,2749,2750,23],{},[2733,2747,2748],{},"Assuming sheet1.xml is the first tab."," Resolve through ",[14,2751,2752],{},"workbook.xml.rels",[2730,2754,2755,2758,2759,2761,2762,23],{},[2733,2756,2757],{},"Assuming shared strings exist."," Some writers store text inline (",[14,2760,1065],{},") and have no ",[14,2763,195],{},[2730,2765,2766,2769],{},[2733,2767,2768],{},"Editing the XML by hand."," Inspecting is safe; changing a part means keeping indexes, relationships and content types consistent — use a library for edits.",[2730,2771,2772,1321,2775,2778,2779,2782,2783,2786],{},[2733,2773,2774],{},"Huge parts.",[14,2776,2777],{},"ET.fromstring"," loads the whole part; for very large sheets use ",[14,2780,2781],{},"ET.iterparse"," on ",[14,2784,2785],{},"z.open(part)"," and clear elements as you go.",[25,2788,2790],{"id":2789},"conclusion","Conclusion",[10,2792,2793,2794,2796,2797,2799,2800,2802,2803,2805,2806,200,2808,200,2810,35,2812,2814,2815,2817,2818,2820],{},"Open the ",[14,2795,16],{}," with ",[14,2798,34],{},", list its parts, and follow ",[14,2801,388],{}," and its relationships to the sheet you want. Read each ",[14,2804,979],{}," element's ",[14,2807,991],{},[14,2809,987],{},[14,2811,1029],{},[14,2813,1033],{}," to see types, styles, formulas and cached results; resolve text through ",[14,2816,195],{}," and formats through ",[14,2819,1628],{},"; pretty-print parts to read them and diff two packages part by part to see what a tool changed. It is the quickest way to answer \"what is actually in this file?\"",[25,2822,2824],{"id":2823},"frequently-asked-questions","Frequently asked questions",[10,2826,2827,2830],{},[2733,2828,2829],{},"How do I see the XML inside an Excel file?","\nOpen it with zipfile.ZipFile(\"file.xlsx\"), list the parts with namelist(), and read any part, such as xl\u002Fworksheets\u002Fsheet1.xml, with z.read(). Parse it with xml.etree.ElementTree or pretty-print it with xml.dom.minidom.",[10,2832,2833,2836],{},[2733,2834,2835],{},"What does t=\"s\" mean in an xlsx cell?","\nThe cell's value is an index into the shared strings table in xl\u002FsharedStrings.xml. Other types are t=\"str\" for a formula's text result, t=\"inlineStr\" for inline text, t=\"b\" for booleans and t=\"e\" for errors; numbers and dates have no t attribute or t=\"n\".",[10,2838,2839,2842],{},[2733,2840,2841],{},"How do I find which XML file holds a given sheet?","\nLook up the sheet's r:id in xl\u002Fworkbook.xml, then find the relationship with that Id in xl\u002F_rels\u002Fworkbook.xml.rels; its Target is the worksheet part. The file numbering does not necessarily follow the tab order.",[10,2844,2845,2848],{},[2733,2846,2847],{},"How can I tell which program last saved an Excel file?","\nRead the Application element in docProps\u002Fapp.xml, but treat it as a hint: XlsxWriter, for example, writes Microsoft Excel there. The structure is more telling — inline strings suggest openpyxl, a shared-string table with cached zero formula results suggests XlsxWriter, and a calcChain.xml part suggests Excel itself.",[25,2850,2852],{"id":2851},"related","Related",[2727,2854,2855,2861,2868,2875],{},[2730,2856,2857,2858,2860],{},"Up one level: ",[19,2859,22],{"href":21}," — every format and how to move between them.",[2730,2862,2863,2867],{},[19,2864,2866],{"href":2865},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-excel-repaired-content-after-writing-with-python\u002F","Fix \"Excel Found Unreadable Content\" After Writing with Python"," — where inspecting the XML pays off.",[2730,2869,2870,2874],{},[19,2871,2873],{"href":2872},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fhow-openpyxl-stores-python-values-in-cells\u002F","How openpyxl Stores Python Values in Cells"," — the library view of the same cell types.",[2730,2876,2877,2881],{},[19,2878,2880],{"href":2879},"\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-excel-files-inside-a-zip-archive-with-python\u002F","Read Excel Files Inside a ZIP Archive with Python"," — when the workbook itself is inside another ZIP.",[2883,2884,2885],"style",{},"html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}",{"title":54,"searchDepth":72,"depth":72,"links":2887},[2888,2889,2890,2891,2892,2893,2894,2895,2896,2897,2898],{"id":27,"depth":72,"text":28},{"id":46,"depth":72,"text":47},{"id":381,"depth":72,"text":382},{"id":746,"depth":72,"text":747},{"id":1608,"depth":72,"text":1609},{"id":2118,"depth":72,"text":2119},{"id":2282,"depth":72,"text":2283},{"id":2724,"depth":72,"text":2725},{"id":2789,"depth":72,"text":2790},{"id":2823,"depth":72,"text":2824},{"id":2851,"depth":72,"text":2852},"2026-10-02","An .xlsx file is a ZIP of XML parts, and looking inside answers questions no library will: list the parts with zipfile, follow workbook.xml and its relationships to the right sheet file, decode cells and their t= types, resolve shared strings and number formats, pretty-print a part, and diff two workbooks part by part to see exactly what a tool changed.","md",[2903,2905,2907,2909],{"q":2829,"a":2904},"Open it with zipfile.ZipFile(\"file.xlsx\"), list the parts with namelist(), and read any part, such as xl\u002Fworksheets\u002Fsheet1.xml, with z.read(). Parse it with xml.etree.ElementTree or pretty-print it with xml.dom.minidom.",{"q":2835,"a":2906},"The cell's value is an index into the shared strings table in xl\u002FsharedStrings.xml. Other types are t=\"str\" for a formula's text result, t=\"inlineStr\" for inline text, t=\"b\" for booleans and t=\"e\" for errors; numbers and dates have no t attribute or t=\"n\".",{"q":2841,"a":2908},"Look up the sheet's r:id in xl\u002Fworkbook.xml, then find the relationship with that Id in xl\u002F_rels\u002Fworkbook.xml.rels; its Target is the worksheet part. The file numbering does not necessarily follow the tab order.",{"q":2847,"a":2910},"Read the Application element in docProps\u002Fapp.xml, but treat it as a hint: XlsxWriter, for example, writes Microsoft Excel there. The structure is more telling — inline strings suggest openpyxl, a shared-string table with cached zero formula results suggests XlsxWriter, and a calcChain.xml part suggests Excel itself.","inspect the xml inside an xlsx file",null,{"breadcrumb":2914},[2915,2917,2920],{"name":2916,"item":1015},"Home",{"name":2918,"item":2919},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":22,"item":21},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Finspect-the-xml-inside-an-xlsx-file-with-python",{"title":2923,"description":2924},"Inspect the XML Inside an Excel .xlsx File with Python","Open an .xlsx as a ZIP and read its XML with zipfile and ElementTree: the package parts, workbook.xml and relationships, cell types (s, str, b, e, inlineStr), sharedStrings, styles and numFmts, pretty-printing, and diffing two files part by part.","inspect-the-xml-inside-an-xlsx-file-with-python","getting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Finspect-the-xml-inside-an-xlsx-file-with-python\u002Findex",[2928,2929],"file-formats","troubleshooting","how-to","Jt-Ku1y04LztLwsROD2QgrOWVb0N5epmwZZTE6W0wkY",[2933,2937],{"title":2934,"path":2935,"stem":2936,"children":-1},"Extract Tables from a PDF into Excel with Python","\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fextract-tables-from-a-pdf-into-excel-with-python","getting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fextract-tables-from-a-pdf-into-excel-with-python\u002Findex",{"title":2938,"path":2939,"stem":2940,"children":-1},"Read an Excel File from a URL or Bytes in Python","\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fread-an-excel-file-from-a-url-or-bytes-in-python","getting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fread-an-excel-file-from-a-url-or-bytes-in-python\u002Findex",[2942,2944],{"path":2943,"title":22},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions",{"path":2945,"title":2918},"\u002Fgetting-started-with-python-excel-automation",[],[2948,2951,2954,2958,2961,2965],{"path":2949,"title":2950,"kind":2930},"\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fconvert-excel-files-to-parquet-with-python","Convert Excel Files to Parquet with Python",{"path":2952,"title":2953,"kind":2930},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Fconvert-excel-to-csv-with-python","Convert Excel to CSV with Python",{"path":2955,"title":2956,"kind":2957},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fexcel-vs-csv-vs-parquet-for-python-data-pipelines","Excel vs CSV vs Parquet for Python Data Pipelines","compare",{"path":2959,"title":2960,"kind":2957},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpick-an-excel-engine-for-xlsx-xlsm-xls-xlsb-and-ods","Pick an Excel Engine for .xlsx, .xlsm, .xls, .xlsb and .ods",{"path":2962,"title":2963,"kind":2964},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Ffix-garbled-characters-in-excel-data","Fix Garbled Characters Like \"CafÃ©\" and \"â€™\" in Excel Data","fix",{"path":2966,"title":2967,"kind":2930},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fextract-vba-macro-code-from-an-excel-file","Extract VBA Macro Code from an Excel File",1790972059294]