You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用LINQ读取XML后同时验证构建日志的多个关联条件?

问题背景与需求

我负责的项目需要读取XML中各构建区域的预期构建结果,与构建日志对比以判断构建是否通过。目前通过LINQ读取XML时,每个条件被拆分为单独条目,但循环检查构建成功状态时,需要同时验证同一日志行的多个关联条件(例如ParseISLogStats对应的BuildProject和BaseBuildArea必须匹配同一条日志),否则会匹配到错误的日志行。此外,部分场景存在两个成功条件,需要实现可同时检查这类多条件的方法。


示例数据

XML预期结果示例

<?xml version="1.0" encoding="UTF-8"?>
<BuildVerification>
    <codeFreezeTime>19:00</codeFreezeTime>
    <!-- 省略其他结构 -->
    <build>
        <BuildMachine>Server01</BuildMachine>
        <Process>
            <ProcessName>ParseISLogStats</ProcessName>
            <Condition>
                <SuccessCriteria>
                    <ConditionName>BuildProject</ConditionName>
                    <ConditionValue>DInstallerBuild</ConditionValue>
                    <StartTimeHeader>StartTime</StartTimeHeader>
                    <!-- 其他条件字段 -->
                </SuccessCriteria>
                <SuccessCriteria>
                    <Field1>Status</Field1>
                    <Comparison1>==</Comparison1>
                    <Value1>Success</Value1>
                    <!-- 其他条件字段 -->
                </SuccessCriteria>
            </Condition>
        </Process>
    </build>
</BuildVerification>

构建日志示例

StartTime           EndTime             Day Elapsed     sec Status  BuildProj       ...
04/16/24 21:57:31   04/16/24 22:02:46   Tue 00:05:15    315 Success DInstallerBuild ...

现有核心代码

ReadXml方法

void ReadXml()
{
    int i_results = 0;
    string finalPathXml = Path.GetFullPath(Path.Combine(newPath, @"BuildVerificationBuildAttributes_t.xml"));
    XDocument xmlDoc1 = XDocument.Load(finalPathXml);
    var results = xmlDoc1.Descendants("build")
        .SelectMany(b => b.Descendants("Process")
        .SelectMany(p => p.Descendants("Condition")
        .SelectMany(c =>c.Descendants("SuccessCriteria")
        .Select(sc => new
        {
            buildMach = (string)b.Element("BuildMachine"),
            p1 = (string)p.Element("ProcessName"),
            // 省略其他字段映射
            startTimeHeader = (string)sc.Element("StartTimeHeader"),
            cName = (string)sc.Element("ConditionName"),
            cValue = (string)sc.Element("ConditionValue"),
            field1 = (string)sc.Element("Field1"),
            comparison1 = (string)sc.Element("Comparison1"),
            val = (string)sc.Element("Value1")
        })))).ToList();
    foreach (var cur in results)
    {
        i_results += ParseLogFile(codeFreezeTime, cur.startTimeHeader, cur.buildMach, cur.p1, cur.cName, cur.cValue, cur.f1, cur.c1, cur.v1);
    }
}

ParseLogFile方法

int ParseLogFile(string codeFreezeTime, string startTimeHeader, string serverName, string logName, string cName, string cValue, string field1, string comparison1, string val)
{
    int i_results = 0;
    DataTable dataTable = ReadDataTable(finalPath);
    foreach (DataRow row in dataTable.Rows)
    {
        if (Regex.IsMatch((row[startTimeHeader]).ToString(), @"^\d+"))
        {
            // 日期检查与单个条件验证逻辑
            // ...
        }
    }
    return i_results;
}

解决方案

1. 重构XML数据读取逻辑:按关联条件分组

原来的SelectMany会把所有SuccessCriteria拆分为独立条目,导致无法关联同一日志行的多个条件。现在需要按Process或Condition分组,将同一组的所有条件收集为一个集合:

void ReadXml()
{
    int i_results = 0;
    string finalPathXml = Path.GetFullPath(Path.Combine(newPath, @"BuildVerificationBuildAttributes_t.xml"));
    XDocument xmlDoc1 = XDocument.Load(finalPathXml);

    // 按build -> Process分组,收集同一Process下的所有关联条件
    var groupedResults = xmlDoc1.Descendants("build")
        .Select(b => new
        {
            BuildMachine = (string)b.Element("BuildMachine"),
            Processes = b.Descendants("Process")
                .Select(p => new
                {
                    ProcessName = (string)p.Element("ProcessName"),
                    // 收集当前Process下的所有SuccessCriteria条件
                    SuccessConditions = p.Descendants("Condition")
                        .SelectMany(c => c.Descendants("SuccessCriteria"))
                        .Select(sc => new
                        {
                            StartTimeHeader = (string)sc.Element("StartTimeHeader"),
                            ConditionName = (string)sc.Element("ConditionName"),
                            ConditionValue = (string)sc.Element("ConditionValue"),
                            Field = (string)sc.Element("Field1"),
                            Comparison = (string)sc.Element("Comparison1"),
                            Value = (string)sc.Element("Value1")
                        })
                        .ToList(),
                    // 可选:读取Condition的逻辑类型(and/or)
                    LogicType = (string)p.Element("Condition")?.Attribute("logic") ?? "and"
                })
                .ToList()
        })
        .ToList();

    foreach (var build in groupedResults)
    {
        foreach (var process in build.Processes)
        {
            // 传入一组关联条件,一次性验证同一日志行
            i_results += ParseLogFileWithMultipleConditions(codeFreezeTime, build.BuildMachine, process.ProcessName, process.SuccessConditions, process.LogicType);
        }
    }
}

2. 实现多条件验证方法

新增方法接收一组条件,遍历日志行时验证当前行是否满足所有(或任一)关联条件,避免匹配错误行:

int ParseLogFileWithMultipleConditions(string codeFreezeTime, string serverName, string logName, List<dynamic> successConditions, string logicType)
{
    int i_results = 0;
    DataTable dataTable = ReadDataTable(finalPath);
    if (!successConditions.Any()) return i_results;

    foreach (DataRow row in dataTable.Rows)
    {
        // 跳过无效时间行
        if (!Regex.IsMatch(row[successConditions[0].StartTimeHeader].ToString(), @"^\d+"))
            continue;

        // 验证通用条件:日期、服务器名、日志名等
        if (!ValidateGeneralConditions(row, codeFreezeTime, serverName, logName))
            continue;

        // 根据逻辑类型验证条件
        bool isConditionsMet = false;
        if (logicType.Equals("and", StringComparison.OrdinalIgnoreCase))
        {
            // 需满足所有关联条件
            isConditionsMet = successConditions.All(cond => ValidateSingleCondition(row, cond));
        }
        else if (logicType.Equals("or", StringComparison.OrdinalIgnoreCase))
        {
            // 需满足任一成功条件
            isConditionsMet = successConditions.Any(cond => ValidateSingleCondition(row, cond));
        }

        if (isConditionsMet)
        {
            i_results++;
            // 找到匹配行后可break,避免重复计数(根据业务需求调整)
            break;
        }
    }
    return i_results;
}

// 抽离单个条件验证逻辑,复用代码
bool ValidateSingleCondition(DataRow row, dynamic condition)
{
    // 实现单个条件的验证逻辑,示例:
    if (!string.IsNullOrEmpty(condition.ConditionName))
    {
        if (condition.ConditionName == "BuildProject" && row["BuildProj"].ToString() == condition.ConditionValue)
            return true;
        // 其他ConditionName类型的验证
    }

    if (!string.IsNullOrEmpty(condition.Field))
    {
        string rowValue = row[condition.Field].ToString();
        switch (condition.Comparison)
        {
            case "==":
                return rowValue == condition.Value;
            case ">":
                if (int.TryParse(rowValue, out int rowInt) && int.TryParse(condition.Value, out int condInt))
                    return rowInt > condInt;
                break;
            // 其他比较逻辑
        }
    }

    return false;
}

// 抽离通用条件验证逻辑
bool ValidateGeneralConditions(DataRow row, string codeFreezeTime, string serverName, string logName)
{
    // 实现日期检查、服务器名匹配、日志名匹配等通用逻辑
    // 示例:验证构建时间晚于codeFreezeTime
    // ...
    return true;
}

3. 可选:扩展XML结构支持逻辑类型

如果需要区分条件是“同时满足”还是“任一满足”,可以给Condition节点添加logic属性:

<Condition logic="and">
    <SuccessCriteria>...</SuccessCriteria>
    <SuccessCriteria>...</SuccessCriteria>
</Condition>

读取时将该属性纳入分组结果,验证时根据属性选择All或Any逻辑。


内容的提问来源于stack exchange,提问作者Michele

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 18:30:54