使用C#与OpenXML SDK操作Word文档遇CS0103错误求助
解决C# + OpenXML SDK处理Word文档时的CS0103错误及逻辑优化
我来帮你拆解这个问题并给出修复方案:
首先,CS0103错误的根源
原始代码里,你遍历子标题的foreach循环是在遍历章节的foreach循环外部的。c是第一个循环的局部变量,只在第一个循环的代码块内有效,到第二个循环里就找不到这个变量了——这就是编译器报错“名称‘c’在当前上下文中不存在”的核心原因。
你修改后的代码把第二个循环移到了第一个里面,本来可以解决作用域问题,但又引入了新bug:
- 注释掉了
MySqlConnection的创建语句,导致conn未初始化就调用Open(),会触发空引用异常 - 把章节的筛选条件从
Contains("Chapter")改成了Contains("Sezione"),如果这不是你的实际业务需求,这是个不必要的修改
完整修复后的代码
protected void UploadButton_Click(object sender, EventArgs e) { if (FileUploadControl.HasFile && FileUploadControl.PostedFile.ContentLength > 0) { try { var allowedExtensions = new string[] { "docx" }; var extension = Path.GetExtension(FileUploadControl.PostedFile.FileName).ToLower().Replace(".", ""); if (allowedExtensions.Contains(extension)) { string filename = Path.GetFileName(FileUploadControl.FileName); string filePath = Server.MapPath("public/") + filename; FileUploadControl.SaveAs(filePath); StatusLabel.Text = "Upload status: File uploaded!"; using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(filePath, true)) { var body = wordDoc.MainDocumentPart.Document.Body; string paras = ""; string connectionString = ConfigurationManager.ConnectionStrings["cn"].ConnectionString; // 遍历所有包含"Chapter"的章节段落 foreach (Paragraph chapterPara in body.Descendants<Paragraph>().Where(p => p.InnerText.Contains("Chapter"))) { string chapterText = chapterPara.InnerText; paras += chapterText + "<br/>"; // 插入章节到Chapters表 string insertChapterSql = @"INSERT IGNORE INTO Chapters (chapter) VALUES (?);"; using (MySqlConnection conn = new MySqlConnection(connectionString)) { conn.Open(); using (MySqlCommand cmd = new MySqlCommand(insertChapterSql, conn)) { cmd.Parameters.AddWithValue("param1", chapterText); cmd.ExecuteNonQuery(); } } // 遍历符合条件的粗体子标题(以"- "开头) foreach (Paragraph subPara in body.Descendants<Paragraph>().Where(p => p.InnerText.StartsWith("- "))) { bool isBold = false; foreach (Run run in subPara.Descendants<Run>()) { // 先判断RunProperties是否为空,避免空引用异常 if (run.RunProperties != null && run.RunProperties.Bold != null) { isBold = true; break; // 只要有一个Run是粗体,就判定为粗体子标题 } } if (isBold) { string subText = subPara.InnerText; paras += subText + "<br/>"; // 插入子标题到subheading表,关联当前章节 string insertSubSql = @"INSERT IGNORE INTO subheading (subheading, chapter) VALUES (?, ?);"; using (MySqlConnection conn = new MySqlConnection(connectionString)) { conn.Open(); using (MySqlCommand cmd = new MySqlCommand(insertSubSql, conn)) { cmd.Parameters.AddWithValue("param1", subText); cmd.Parameters.AddWithValue("param2", chapterText); cmd.ExecuteNonQuery(); } } } } } Response.Write(paras); } } else { StatusLabel.Text = "Upload status: Only DOCX files are accepted!"; } } catch (Exception ex) { StatusLabel.Text = $"Upload status: The file could not be uploaded. The following error occurred: {ex.Message}"; } } }
关键修改点说明
- 修复变量作用域:把遍历子标题的循环放到章节循环内部,确保当前章节的文本变量能被子标题的插入逻辑正确引用
- 修正数据库连接:恢复了
MySqlConnection的using块,确保连接被正确创建、使用和释放,避免资源泄漏 - 增加空值判断:检查粗体属性前先判断
run.RunProperties是否为null,防止空引用异常 - 优化代码可读性:把模糊的变量名
c、p改成chapterPara、subPara,逻辑更清晰 - 提取重复配置:把数据库连接字符串提取到外层,避免重复读取配置
额外优化建议
当前代码是全文档扫描子标题,可能会把所有章节的子标题都关联到每个章节。如果你的Word文档是「章节→对应子标题→下一个章节」的结构,可以修改逻辑,只查找当前章节段落之后的子标题,直到遇到下一个章节段落,这样关联会更准确。
内容的提问来源于stack exchange,提问作者Chevy Mark Sunderland
相关产品推荐
相关产品推荐

