รูปแบบการออกแบบที่ดีสำหรับการสร้างไฟล์ Excel (xlsx) เป็นรหัสคืออะไร


12

ดูการอัปเดตของฉันที่ด้านล่างสำหรับข้อมูลเพิ่มเติม


บางครั้งฉันมีโครงการที่ฉันต้องส่งออกข้อมูลบางอย่างเป็นไฟล์ Excel (รูปแบบ xlsx) กระบวนการมักจะ:

  1. ผู้ใช้คลิกปุ่มบางปุ่มในแอปพลิเคชันของฉัน

  2. รหัสของฉันเรียกใช้แบบสอบถาม DB และประมวลผลผลลัพธ์อย่างใด

  3. รหัสของฉันสร้างไฟล์ * .xlsx โดยใช้ห้องสมุด Excel com interop หรือห้องสมุดบุคคลที่สาม (เช่น Aspose.Cells)

ฉันสามารถค้นหาตัวอย่างรหัสได้อย่างง่ายดายสำหรับวิธีการออนไลน์นี้ แต่ฉันกำลังมองหาวิธีที่มีประสิทธิภาพมากขึ้นในการทำเช่นนี้ ฉันต้องการให้รหัสของฉันเป็นไปตามหลักการออกแบบเพื่อให้แน่ใจว่ารหัสของฉันสามารถบำรุงรักษาและเข้าใจได้ง่าย


นี่คือความพยายามครั้งแรกของฉันในการสร้างไฟล์ xlsx ที่มีลักษณะ:

var wb = new Workbook();
var ws = wb.Worksheets[0];
ws.Cells[0, 0].Value = "Header";
ws.Cells[1, 0].Value = "Row 1";
ws.Cells[2, 0].Value = "Row 2";
ws.Cells[3, 0].Value = "Row 3";
wb.Save(path);

จุดเด่น: ไม่มาก มันใช้งานได้ดี

จุดด้อย:

  • การอ้างอิงเซลล์เป็นฮาร์ดโค้ดดังนั้นฉันจึงมีหมายเลขเวทย์มนตร์ที่เกลื่อนไปทั่วรหัสของฉัน
  • เป็นการยากที่จะเพิ่มหรือลบคอลัมน์และแถวโดยไม่ต้องอัปเดตการอ้างอิงเซลล์จำนวนมาก
  • ฉันต้องเรียนรู้ห้องสมุดบุคคลที่สาม ห้องสมุดบางแห่งมีการใช้งานเหมือนห้องสมุดอื่น ๆ แต่ก็ยังมีปัญหาอยู่ ฉันมีปัญหาที่ไลบรารี com interop ใช้การอ้างอิงเซลล์แบบ 1 ฐานขณะที่ Aspose.Cells ใช้การอ้างอิงเซลล์แบบ 0

ต่อไปนี้เป็นวิธีแก้ไขปัญหาข้อหนึ่งที่กล่าวถึงข้อด้อยบางอย่างที่ฉันระบุไว้ด้านบน ฉันต้องการรักษาตารางของข้อมูลเป็นวัตถุของตัวเองที่สามารถเคลื่อนย้ายไปมาและเปลี่ยนแปลงโดยไม่ต้องขุดเข้าไปในการจัดการเซลล์และรบกวนการอ้างอิงเซลล์อื่น ๆ นี่คือรหัสเทียมบางส่วน:

var headers = new Block(new string[] { "Col 1", "Col 2", "Col 3" });
var body = new Block(new string[,]
    {
        { "Row 1", "Row 1", "Row 1" },
        { "Row 2", "Row 2", "Row 2" },
        { "Row 3", "Row 3", "Row 3" }
    });

body.PutBelow(headers);

ในฐานะที่เป็นส่วนหนึ่งของการแก้ปัญหานี้ฉันจะมีออบเจกต์ BlockEngine บางส่วนที่รับคอนเทนเนอร์ของบล็อกและดำเนินการจัดการเซลล์ที่จำเป็นในการส่งออกข้อมูลเป็นไฟล์ * .xlsx วัตถุบล็อกสามารถมีการจัดรูปแบบที่แนบมากับมัน

ข้อดี:

  • สิ่งนี้จะลบหมายเลขเวทย์มนตร์ส่วนใหญ่ที่มีรหัสเริ่มต้นของฉัน
  • สิ่งนี้ซ่อนรหัสการจัดการเซลล์จำนวนมากแม้ว่าการจัดการเซลล์ยังจำเป็นในวัตถุ BlockEngine ที่ฉันกล่าวถึง
  • ง่ายกว่ามากในการเพิ่มและลบแถวโดยไม่ส่งผลต่อส่วนอื่น ๆ ของสเปรดชีต

จุดด้อย:

  • ยังคงเพิ่มหรือลบคอลัมน์ได้ยาก ถ้าฉันต้องการสลับตำแหน่งของคอลัมน์ที่สองและสามฉันจะต้องสลับเนื้อหาของเซลล์โดยตรง ในกรณีนี้จะเป็นการแก้ไขแปดครั้งดังนั้นจึงมีโอกาสแปดครั้งที่จะทำผิดพลาด
    • หากฉันมีการจัดรูปแบบใด ๆ สำหรับสองคอลัมน์เหล่านั้นฉันต้องอัปเดตสิ่งนั้นด้วย
  • วิธีนี้ไม่รองรับการวางบล็อกแนวนอน ฉันสามารถวางหนึ่งบล็อกด้านล่างอื่นเท่านั้น แน่นอนว่าฉันสามารถมีtableRight.PutToRightOf(tableLeft)แต่นั่นจะทำให้เกิดปัญหาหาก tableRight และ tableLeft มีจำนวนแถวที่แตกต่างกัน เมื่อต้องการวางตารางเครื่องยนต์จะต้องตระหนักถึงตารางอื่น ๆ ทุก ๆ ดูเหมือนว่าฉันจะมีความซับซ้อนโดยไม่จำเป็น
  • ฉันยังต้องเรียนรู้รหัสของบุคคลที่สามถึงแม้ว่าจะมีเลเยอร์ abstraction ผ่าน Block objects และ BlockEngine รหัสจะน้อยลงควบคู่ไปกับไลบรารี่ของบุคคลที่สามมากกว่าความพยายามครั้งแรกของฉัน ถ้าฉันต้องการสนับสนุนตัวเลือกการจัดรูปแบบที่แตกต่างกันจำนวนมากในแบบคู่ขนานอย่างอิสระฉันอาจต้องเขียนโค้ดจำนวนมาก BlockEngine ของฉันจะยุ่งมาก

นี่คือโซลูชันที่ใช้เส้นทางอื่น นี่คือกระบวนการ:

  1. ฉันใช้ข้อมูลรายงานของฉันและสร้างไฟล์ xml ในบางรูปแบบที่ฉันเลือก

  2. ฉันใช้การแปลง xsl เพื่อแปลงไฟล์ xml เป็นไฟล์ Excel Spreadsheet ของ Excel 2003

  3. จากนั้นฉันก็แปลงสเปรดชีท xml เป็นไฟล์ xlsx โดยใช้ห้องสมุดบุคคลที่สาม

ฉันพบหน้านี้ซึ่งอธิบายกระบวนการที่คล้ายกันและรวมถึงตัวอย่างรหัส

ข้อดี:

  • วิธีการแก้ปัญหานี้แทบจะไม่มีการจัดการเซลล์ คุณใช้ xsl / xpath แทนในการทำกิจวัตรของคุณ เพื่อสลับสองคอลัมน์ในตารางคุณย้ายทั้งคอลัมน์ในไฟล์ xsl ไม่เหมือนกับโซลูชันอื่น ๆ ของฉันซึ่งต้องใช้การแลกเปลี่ยนเซลล์
  • ในขณะที่คุณยังต้องการห้องสมุดบุคคลที่สามที่สามารถแปลงสเปรดชีต Excel 2003 XML เป็นไฟล์ xlsx นั่นคือทั้งหมดที่คุณต้องการสำหรับห้องสมุด จำนวนรหัสที่คุณต้องเขียนที่จะโทรเข้าไปในห้องสมุดบุคคลที่สามนั้นมีขนาดเล็กมาก
  • ฉันคิดว่าวิธีนี้เป็นวิธีที่ง่ายที่สุดที่จะเข้าใจและต้องการจำนวนน้อยที่สุดของรหัส
    • รหัสที่สร้างข้อมูลในรูปแบบ xml ของฉันจะง่าย
    • ไฟล์ xsl จะซับซ้อนเพียงเพราะสเปรดชีต XML ของ Excel 2003 มีความซับซ้อน อย่างไรก็ตามมันง่ายที่จะตรวจสอบผลลัพธ์ของไฟล์ xsl: เพียงแค่เปิดผลลัพธ์ใน Excel และตรวจสอบข้อความแสดงข้อผิดพลาด
    • ง่ายในการสร้างตัวอย่างไฟล์ Excel Spreadsheet XML 2003: เพียงสร้างสเปรดชีตที่ดูเหมือนไฟล์ xlsx ที่คุณต้องการแล้วบันทึกเป็น Excel Spreadsheet XML 2003

จุดด้อย:

  • Excel 2003 XML Spreadsheets ไม่รองรับคุณสมบัติบางอย่าง คุณไม่สามารถปรับความกว้างคอลัมน์โดยอัตโนมัติได้ คุณไม่สามารถรวมภาพไว้ในหัวกระดาษหรือท้ายกระดาษได้ หากคุณกำลังจะส่งออกไฟล์ผลลัพธ์ xlsx ไปยัง pdf คุณจะไม่สามารถตั้งค่าที่คั่นหนังสือแบบ pdf (ฉันแฮ็กแก้ไขด้วยวิธีนี้โดยใช้ความเห็นของเซลล์) คุณต้องทำสิ่งนี้โดยใช้ห้องสมุดบุคคลที่สาม
  • ต้องการไลบรารีที่รองรับ Excel Spreadsheets XML 2003
  • ใช้รูปแบบไฟล์ MS Office อายุ 11 ปี

หมายเหตุ: ฉันรู้ว่าไฟล์ xlsx เป็นไฟล์ zip จริงที่มีไฟล์ xml แต่การจัดรูปแบบ xml นั้นซับซ้อนเกินไปสำหรับจุดประสงค์ของฉัน


ในที่สุดฉันได้พิจารณาถึงวิธีการแก้ปัญหาที่เกี่ยวข้องกับ SSRS แต่ดูเหมือนจะอ้วนเกินไปสำหรับวัตถุประสงค์ของฉัน


กลับไปที่คำถามเริ่มต้นรูปแบบการออกแบบที่ดีสำหรับการสร้างไฟล์ Excel ในรหัสคืออะไร ฉันสามารถนึกถึงวิธีแก้ปัญหาบางอย่าง แต่ดูเหมือนจะไม่มีใครเห็นอุดมคติ แต่ละคนมีข้อเสีย


อัปเดต:ดังนั้นฉันจึงลองทั้งโซลูชัน BlockEngine และ XML Spreadsheet ของฉันเพื่อสร้างไฟล์ XLSX ที่คล้ายกัน นี่คือความคิดเห็นของฉันของพวกเขา:

  • โซลูชัน BlockEngine:

    • สิ่งนี้ต้องการรหัสมากเกินไปเมื่อพิจารณาทางเลือก
    • ฉันพบว่ามันง่ายเกินไปที่จะเขียนทับบล็อกหนึ่งกับอีกบล็อกหนึ่งหากฉันมีการชดเชยที่ไม่ถูกต้อง
    • ฉันกล่าวว่าการจัดรูปแบบสามารถแนบที่ระดับบล็อก ฉันพบสิ่งนี้จะไม่ดีไปกว่าการจัดรูปแบบแยกต่างหากจากเนื้อหาบล็อก ฉันไม่สามารถคิดวิธีที่ดีในการรวมเนื้อหาและการจัดรูปแบบ ฉันไม่สามารถหาวิธีที่ดีในการแยกพวกเขาออกจากกัน มันเป็นระเบียบ
  • โซลูชันสเปรดชีต XML:

    • ฉันจะไปกับการแก้ปัญหานี้ในตอนนี้
    • มันหมีซ้ำว่าวิธีนี้ต้องใช้รหัสน้อยกว่ามาก ฉันกำลังแทนที่ BlockEngine ด้วย Excel อย่างมีประสิทธิภาพ ฉันยังคงต้องการแฮ็กสำหรับคุณลักษณะเช่นบุ๊คมาร์คและตัวแบ่งหน้า
    • รูปแบบสเปรดชีต XML มีความพิถีพิถัน แต่การเปลี่ยนแปลงเพียงเล็กน้อยนั้นง่ายและเปรียบเทียบผลลัพธ์กับไฟล์ที่มีอยู่ในโปรแกรม Diff ที่คุณชื่นชอบ และเมื่อคุณเข้าใจถึงความแปลกประหลาดบางอย่างคุณสามารถใส่มันเข้าไปในนั้นแล้วลืมมันไปจากตรงนั้น
    • ฉันยังคงกังวลว่าโซลูชันนี้อาศัยรูปแบบไฟล์ Excel รุ่นเก่ากว่า
    • ไฟล์ XSLT ที่ฉันสร้างนั้นใช้งานง่าย การจัดการกับการจัดรูปแบบทำได้ง่ายกว่าที่นี่ด้วยโซลูชั่น BlockEngine

คำตอบ:


7

หากคุณต้องการบางสิ่งที่ทำงานได้ดีสำหรับคุณฉันขอแนะนำให้คุณคุ้นเคยกับแนวคิด "ซับซ้อนโดยไม่จำเป็น" ... นั่นคือลักษณะของการจัดการกับรูปแบบไฟล์ Microsoft Office

ฉัน (เรียงลำดับ) เหมือนกับความคิดของคุณของ "บล็อก" ... ฉันจะสร้างวัตถุบล็อกย่อยที่คลาสเช่นตารางที่มีคอลัมน์และแถวโดยอิสระจากความคิดของเซลล์ จากนั้นใช้เครื่องมือบล็อกของคุณเพื่อแปลงเป็นไฟล์ XSLS

ฉันเคยใช้OpenXML SDKมาแล้ว แต่ไม่ลองอ่านเอกสารและเริ่มต้นใหม่ สร้างสำเนาที่แน่นอนใน Excel แทนสิ่งที่คุณต้องการบันทึกและตรวจสอบโดยใช้เครื่องมือ Document Reflector มันจะให้รหัส C # ที่คุณต้องการในการสร้างเอกสารซึ่งคุณสามารถเรียนรู้และแก้ไขได้


เอกสาร Office ไม่ได้ "ซับซ้อนโดยไม่จำเป็น" - พวกเขากำลังทำหรืออนุญาตให้มีการดำเนินการการจัดรูปแบบการใช้งานและอื่น ๆ มากมาย
วอร์เรน

5
ผมไม่เถียงว่ารูปแบบไฟล์ตัวเองโดยไม่จำเป็นที่ซับซ้อนมากที่สุดเท่าที่ฉันกำลังเถียงว่าการทำงานกับพวกเขาคือ ตัวอย่างเช่นการใช้ OpenXML SDK ต้องการให้คุณทราบลำดับมายากลที่จะเพิ่มองค์ประกอบ ... การเพิ่มเค้าโครงสไลด์ในงานนำเสนอตัวอย่างเช่นใช้ไม่ได้ คุณต้องเพิ่มลงในสไลด์ก่อนจากนั้นจึงนำเสนอ ทำไม? เพราะ Microsoft เข้ารหัสไลบรารีด้วยวิธีนี้ มีการอ้างอิงแบบวงกลมแปลก ๆ มากมายที่จะจัดการเช่นกัน ฉันเข้าใจรูปแบบที่ต้องการความซับซ้อน แต่การทำงานกับมันไม่ควรเจ็บปวด
mgw854

3

นี่เป็นวิธีแก้ปัญหาที่ฉันใช้บ่อยครั้งในอดีต:

  • สร้างเอกสาร Excel ปกติ (โดยทั่วไปในรูปแบบ xlsx) เช่นเดียวกับเทมเพลตที่มีส่วนหัวคอลัมน์ทั้งหมดรวมถึงชื่อและการจัดรูปแบบเริ่มต้นสำหรับคอลัมน์และอาจจัดรูปแบบสำหรับเซลล์ชื่อเรื่อง

  • ฝังแม่แบบนั้นไว้ในแหล่งข้อมูลของโปรแกรมของคุณ ที่รันไทม์ขั้นตอนแรกคือการแยกแม่แบบเป็นไฟล์ใหม่และวางลงในโฟลเดอร์ปลายทาง

  • ใช้ Interop หรือไลบรารีบุคคลที่สามเพื่อเติมข้อมูลลงใน xlsx ที่สร้างขึ้นใหม่ อย่าอ้างถึงหมายเลขคอลัมน์ hardcoded ให้ใช้ข้อมูลเมตาบางส่วน (ตัวอย่างเช่นส่วนหัวคอลัมน์) เพื่อระบุคอลัมน์ที่ถูกต้อง

ข้อดี:

  • บางอย่างเช่นวิธีบล็อกของคุณตอนนี้ทำงานได้ดีขึ้น ตัวอย่างเช่นการสลับคอลัมน์: ไม่จำเป็นต้องเปลี่ยนแปลงอะไรในรหัสบล็อกของคุณเนื่องจากส่วนหัวของคอลัมน์นั้นถูกต้อง

  • ตราบใดที่คอลัมน์ของคุณมีการจัดรูปแบบที่ไม่ซ้ำใครการจัดรูปแบบส่วนใหญ่สามารถทำได้โดยตรงใน Excel โดยใช้แม่แบบของคุณ ที่ให้ความรู้สึกแบบ WYSIWYG พร้อมกับอิสระในการใช้ตัวเลือกการจัดรูปแบบใด ๆ ที่มีใน Excel โดยไม่จำเป็นต้องเขียนโค้ดสำหรับมัน

จุดด้อย:

  • คุณยังจำเป็นต้องใช้ lib หรือ Interop ของบุคคลที่สาม ฉันพูดถึง Interop ช้าไหม?

  • เมื่อส่วนหัวของคอลัมน์เปลี่ยนไปในแม่แบบของคุณคุณจะต้องปรับเปลี่ยนรหัสของคุณด้วย (แต่สามารถตรวจพบได้โดยง่ายด้วยการมีขั้นตอนการตรวจสอบความถูกต้องซึ่งจะส่งสัญญาณหากมีคอลัมน์ที่ขาดหายไป

  • เมื่อคุณต้องการจัดรูปแบบไดนามิกของเซลล์ที่แตกต่างกันในคอลัมน์เดียวกันคุณยังต้องจัดการกับสิ่งนั้นในรหัส

ตามคำแนะนำทั่วไปวิธีใดก็ตามที่คุณเลือก: มันมีข้อดีที่จะแยกเลย์เอาต์ออกจากเนื้อหาและใช้ประโยชน์จากโซลูชันที่เปิดเผย


0

มีสองสิ่งที่ควรพิจารณา:

  • ความซับซ้อนของการสร้างไฟล์ในรูปแบบที่กำหนด
  • ความไวของรหัสที่จะแตกเมื่อโครงสร้างของเนื้อหาของไฟล์ที่ต้องการเปลี่ยนแปลง

เกี่ยวกับครั้งแรก:

หากสเปรดชีตที่คุณต้องการสร้างไม่มีการจัดรูปแบบหรือสูตรใด ๆ แสดงว่าคุณค่อนข้างตรงไปตรงมาที่จะสร้างไฟล์ CSV หรือคั่นด้วยแท็บแทน XLSX จริง Excel จะเปิดไฟล์เหล่านี้ตามค่าเริ่มต้นในพีซีจำนวนมาก สิ่งนี้จะไม่ช่วยคุณในการเขียนโค้ดอย่างหนักรอบ ๆ คอลัมน์และแถว แต่มันจะช่วยให้คุณประหยัดมากขึ้นในการจัดการโมเดลวัตถุของ Excel

หากคุณต้องการการจัดรูปแบบหรือสูตรการทำงานกับโมเดลวัตถุของ Excel นั้นเป็นวิธีที่เหมาะสมในการดำเนินการโดยเฉพาะอย่างยิ่งถ้าคุณสร้างสเปรดชีตที่ไม่ได้เป็น "ฮาร์ดโค้ด" เกินไป กล่าวอีกนัยหนึ่งถ้าสเปรดชีตของคุณใช้สูตรสัมพัทธ์และชื่อช่วงอย่างเหมาะสมก็สามารถไปพร้อมกับการเข้ารหัสตัวเลขเวทมนตร์น้อยลง

เกี่ยวกับที่สอง:

คุณสามารถทำงานผ่านเซลล์แต่ละเซลล์โดยใช้การอ้างอิงแถวและคอลัมน์อย่างหนักหรือคุณสามารถทำงานกับคอลเลกชันอาร์เรย์ / รายการและforลูปเพื่อสรุปประชากรของเซลล์


ฉันไม่ชัดเจนในคำถามเดิมของฉันที่ฉันต้องการควบคุมการจัดรูปแบบและตัวเลือกการพิมพ์และในโซลูชันของฉัน เกี่ยวกับประเด็นที่สองฉันคิดว่าสิ่งที่คุณอ้างถึงคือสิ่งที่ฉันอธิบายในBlockEngineวิธีแก้ปัญหาของฉัน ฉันสามารถเอาวัตถุIList<IBusinessObject>และถ่มน้ำลายออกมาBlockได้ ข้อดีและข้อเสียยังคงเหมือนเดิม
user2023861
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.