添加项目文件。
This commit is contained in:
258
TechHelper.Client/Exam/Exam.cs
Normal file
258
TechHelper.Client/Exam/Exam.cs
Normal file
@@ -0,0 +1,258 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Xml.Serialization; // 确保引用此命名空间
|
||||
using System.Collections.Generic;
|
||||
using System.IO; // 用于 XML 反序列化
|
||||
|
||||
namespace TechHelper.Client.Exam
|
||||
{
|
||||
|
||||
[XmlRoot("EP")]
|
||||
public class StringsList
|
||||
{
|
||||
|
||||
[XmlElement("Q")]
|
||||
public List<string> Items { get; set; }
|
||||
}
|
||||
|
||||
// XML 根元素 <EP>
|
||||
[XmlRoot("EP")]
|
||||
public class ExamPaper
|
||||
{
|
||||
// XML 特性:<QGs> 包含 <QG> 列表
|
||||
[XmlArray("QGs")]
|
||||
[XmlArrayItem("QG")]
|
||||
[JsonProperty("QuestionGroups")]
|
||||
public List<QuestionGroup> QuestionGroups { get; set; } = new List<QuestionGroup>();
|
||||
}
|
||||
|
||||
[XmlRoot("QG")]
|
||||
public class QuestionGroup
|
||||
{
|
||||
// JSON 特性
|
||||
[JsonProperty("题号")]
|
||||
// XML 特性:作为 <QG Id="X"> 属性
|
||||
[XmlAttribute("Id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[JsonProperty("标题")]
|
||||
[XmlAttribute("T")] // T for Title
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("分值")]
|
||||
[XmlAttribute("S")] // S for Score
|
||||
public int Score { get; set; }
|
||||
|
||||
[JsonProperty("分值问题标记")]
|
||||
[XmlAttribute("SPM")] // SPM for ScoreProblemMarker
|
||||
public string ScoreProblemMarker { get; set; } = ""; // 初始化为空字符串,避免 null
|
||||
|
||||
[JsonProperty("题目引用")]
|
||||
[XmlElement("QR")] // QR for QuestionReference,作为 <QR> 元素
|
||||
public string QuestionReference { get; set; } = ""; // 初始化为空字符串
|
||||
|
||||
[JsonProperty("子题目")]
|
||||
[XmlArray("SQs")] // SQs 包含 <SQ> 列表
|
||||
[XmlArrayItem("SQ")]
|
||||
public List<SubQuestion> SubQuestions { get; set; } = new List<SubQuestion>();
|
||||
|
||||
[JsonProperty("子题组")]
|
||||
[XmlArray("SQGs")] // SQGs 包含 <QG> 列表 (嵌套题组)
|
||||
[XmlArrayItem("QG")]
|
||||
public List<QuestionGroup> SubQuestionGroups { get; set; } = new List<QuestionGroup>();
|
||||
}
|
||||
|
||||
// 子题目类
|
||||
public class SubQuestion
|
||||
{
|
||||
[JsonProperty("子题号")]
|
||||
[XmlAttribute("Id")] // Id for SubId
|
||||
public string SubId { get; set; }
|
||||
|
||||
[JsonProperty("题干")]
|
||||
[XmlAttribute("T")] // T for Text (Stem)
|
||||
public string Stem { get; set; }
|
||||
|
||||
[JsonProperty("分值")]
|
||||
[XmlAttribute("S")] // S for Score
|
||||
public int Score { get; set; } // 分值通常为整数
|
||||
|
||||
[JsonProperty("分值问题标记")]
|
||||
[XmlAttribute("SPM")] // SPM for ScoreProblemMarker
|
||||
public string ScoreProblemMarker { get; set; } = "";
|
||||
|
||||
// 注意:这里的 Options 需要适配 XML 结构 <Os><O V="X"/></Os>
|
||||
// 因此它不再是 List<string>,而是 List<Option>
|
||||
[JsonProperty("选项")]
|
||||
[XmlArray("Os")] // Os 包含 <O> 列表
|
||||
[XmlArrayItem("O")]
|
||||
public List<Option> Options { get; set; } = new List<Option>();
|
||||
|
||||
[JsonProperty("示例答案")]
|
||||
[XmlAttribute("SA")] // SA for SampleAnswer
|
||||
public string SampleAnswer { get; set; } = "";
|
||||
}
|
||||
|
||||
// 选项类,用于适配 <O V="X"/> 结构
|
||||
public class Option
|
||||
{
|
||||
// XML 特性:作为 <O V="X"> 属性
|
||||
[XmlAttribute("V")] // V for Value
|
||||
// JSON 特性:如果 JSON 中的选项是 {"Value": "A"} 这样的对象,则需要 JsonProperty("Value")
|
||||
// 但如果 JSON 选项只是 ["A", "B"] 这样的字符串数组,则此Option类不适合JSON Options
|
||||
// 需要明确你的JSON Options的结构。我假设你JSON Options是 List<string>
|
||||
// 如果是 List<string>,则Options属性在SubQuestion中直接是List<string>,Option类则不需要
|
||||
// 但根据你的精简XML需求,Option类是必要的。
|
||||
// 所以这里需要你自己根据实际JSON Options结构选择。
|
||||
// 为了兼容XML,我会保留Option类,但如果JSON是List<string>,Options属性会很复杂
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
// 独立的服务类来处理序列化和反序列化
|
||||
public static class ExamParser
|
||||
{
|
||||
// JSON 反序列化方法
|
||||
public static List<T> ParseExamJson<T>(string jsonContent)
|
||||
{
|
||||
string cleanedJson = jsonContent.Trim();
|
||||
|
||||
// 移除可能存在的 Markdown 代码块标记
|
||||
if (cleanedJson.StartsWith("```json") && cleanedJson.EndsWith("```"))
|
||||
{
|
||||
cleanedJson = cleanedJson.Substring("```json".Length, cleanedJson.Length - "```json".Length - "```".Length).Trim();
|
||||
}
|
||||
// 移除可能存在的单引号包围(如果 AI 偶尔会这样输出)
|
||||
if (cleanedJson.StartsWith("'") && cleanedJson.EndsWith("'"))
|
||||
{
|
||||
cleanedJson = cleanedJson.Substring(1, cleanedJson.Length - 2).Trim();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 注意:这里假设你的 JSON 根直接是一个 QuestionGroup 列表
|
||||
// 如果你的 JSON 根是 { "QuestionGroups": [...] },则需要先反序列化到 ExamPaper
|
||||
List<T> examQuestions = JsonConvert.DeserializeObject<List<T>>(cleanedJson);
|
||||
return examQuestions;
|
||||
}
|
||||
catch (JsonSerializationException ex)
|
||||
{
|
||||
Console.WriteLine($"JSON 反序列化错误: {ex.Message}");
|
||||
Console.WriteLine($"内部异常: {ex.InnerException?.Message}");
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"处理错误: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region TEST
|
||||
[XmlRoot("User")]
|
||||
public class User
|
||||
{
|
||||
[XmlAttribute("id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[XmlElement("PersonalInfo")]
|
||||
public PersonalInfo PersonalInfo { get; set; }
|
||||
|
||||
[XmlArray("Roles")] // 包装元素 <Roles>
|
||||
[XmlArrayItem("Role")] // 集合中的每个项是 <Role>
|
||||
public List<Role> Roles { get; set; } = new List<Role>();
|
||||
|
||||
// 构造函数,方便测试
|
||||
public User() { }
|
||||
}
|
||||
|
||||
public class PersonalInfo
|
||||
{
|
||||
[XmlElement("FullName")]
|
||||
public string FullName { get; set; }
|
||||
|
||||
[XmlElement("EmailAddress")]
|
||||
public string EmailAddress { get; set; }
|
||||
|
||||
// 构造函数,方便测试
|
||||
public PersonalInfo() { }
|
||||
}
|
||||
|
||||
public class Role
|
||||
{
|
||||
[XmlAttribute("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
// 构造函数,方便测试
|
||||
public Role() { }
|
||||
}
|
||||
#endregion
|
||||
|
||||
// XML 反序列化方法
|
||||
public static T ParseExamXml<T>(string xmlContent)
|
||||
{
|
||||
string cleanedXml = xmlContent.Trim();
|
||||
if (cleanedXml.StartsWith("'") && cleanedXml.EndsWith("'"))
|
||||
{
|
||||
cleanedXml = cleanedXml.Substring(1, cleanedXml.Length - 2);
|
||||
}
|
||||
if (cleanedXml.StartsWith("```xml") && cleanedXml.EndsWith("```"))
|
||||
{
|
||||
cleanedXml = cleanedXml.Substring("```xml".Length, cleanedXml.Length - "```xml".Length - "```".Length).Trim();
|
||||
}
|
||||
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(T));
|
||||
|
||||
using (StringReader reader = new StringReader(cleanedXml))
|
||||
{
|
||||
try
|
||||
{
|
||||
T user = (T)serializer.Deserialize(reader);
|
||||
return user;
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
Console.WriteLine($"XML 反序列化操作错误: {ex.Message}");
|
||||
Console.WriteLine($"内部异常: {ex.InnerException?.Message}");
|
||||
return default(T);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"处理错误: {ex.Message}");
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<QuestionGroup> ParseExamXmlFormQG(string xmlContent)
|
||||
{
|
||||
// 移除可能存在的 Markdown 代码块标记
|
||||
if (xmlContent.StartsWith("```xml") && xmlContent.EndsWith("```"))
|
||||
{
|
||||
xmlContent = xmlContent.Substring("```xml".Length, xmlContent.Length - "```xml".Length - "```".Length).Trim();
|
||||
}
|
||||
|
||||
var serializer = new XmlSerializer(typeof(List<QuestionGroup>), new XmlRootAttribute("QGs"));
|
||||
|
||||
using (StringReader reader = new StringReader(xmlContent))
|
||||
{
|
||||
try
|
||||
{
|
||||
List<QuestionGroup> questionGroups = (List<QuestionGroup>)serializer.Deserialize(reader);
|
||||
return questionGroups;
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
Console.WriteLine($"XML 反序列化操作错误: {ex.Message}");
|
||||
Console.WriteLine($"内部异常: {ex.InnerException?.Message}");
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"处理错误: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user