C#完成XML文档节点的自动计算功能

news2024/12/22 9:38:35

  一个项目涉及XML文档中节点的自动计算,就是XML文档的每个节点都参与运算,要求:

  ⑴如果节点有计算公式则按照计算公式进行;

  ⑵如果节点没有计算公式则该节点的值就是所有子节点的值之和;

  ⑶节点有4种类型,计算节点、输入框、单选节点、多选节点;

    计算节点:汇总;

    输入框:点击该节点弹出输入框用于输入数据;

    单选节点:众多选项中只能选择一个,根据选择项确定该节点的具体值;

    多选节点:众多选项中可以选择多个,该节点的值是所有选择项的和;

  类似下图(实际选项近100个):

  问题是点击任何图标节点后都要完成的自动计算。

  开始的时候,我将所有XML信息加载到Treeview中,包括属性,在Treeview中进行计算,完成后同步到XML文档,这样完成后效果不好,选项多了速度慢,如果计算机配置一般的话有略微的卡顿。

  今天下午,我修改了方法,直接在XML文档中进行操作,使用递归完成节点的自动计算,这样速度很快,并且不需要同步到Treeview中(因为Treeview只是用于显示)。

  1、点击节点

  在Treeview中确定节点,根据节点类型完成图标变化,在XML中找到对应的节点。

  ⑴完成状态标识,如果是Radio则标识单选;如果是Checkbox标识多选;

  ⑵提取Value值,如果是Textbox则是输入值,如果是Radio则是父项value值是点击节点的Value值;如果是Checkbox则父项是所有选择项的value值之和。

  ⑶调用自动计算,如果是Radio或者Checkbox则是从父项的父项开始,如果是Textbox则是从父项开始。

        private void treeView1_MouseDown(object sender, MouseEventArgs e)
        {
            //获取鼠标点击的位置
            TreeNode FocusNode = treeView1.GetNodeAt(e.Location);
            string StrCurrentFullPath = FocusNode.FullPath;
            string StrNodeType = "";
            if (FocusNode != null)
            {
                //获取鼠标点击的位置是否在节点的图标上
                //在Treeview中针对Radio、Checkbox、TextBook分别进行设置
                TreeViewHitTestInfo hitTestInfo = treeView1.HitTest(e.Location);
                if (hitTestInfo.Location == TreeViewHitTestLocations.Image)
                {
                    StrNodeType = FocusNode.Tag.ToString();
                    //鼠标点击了节点的图标
                    switch (StrNodeType)
                    {
                        case "Radio":
                            // 取消同级节点的选中状态
                            foreach (TreeNode node1 in FocusNode.Parent.Nodes)
                            {
                                if (node1 != FocusNode)
                                {
                                    node1.ImageKey = "Radio";
                                    node1.SelectedImageKey = "Radio";
                                }
                            }
                            // 设置当前节点为选中状态
                            FocusNode.ImageKey = "RadioChecked";
                            FocusNode.SelectedImageKey = "RadioChecked";
                            //在XML文档中处理
                            HandleNodeInfoAtXmlContent(StrCurrentFullPath, StrNodeType,"");//在文档中找到该节点并处理

                            //
                            break;
                        case "Checkbox":
                            if (FocusNode.ImageKey == "Checkbox")
                            {
                                FocusNode.ImageKey = "CheckboxChecked";
                                FocusNode.SelectedImageKey = "CheckboxChecked";
                            }
                            else
                            {
                                FocusNode.ImageKey = "Checkbox";
                                FocusNode.SelectedImageKey = "Checkbox";
                            }
                            //在XML文档中处理
                            HandleNodeInfoAtXmlContent(StrCurrentFullPath, StrNodeType,"");//在文档中找到该节点并处理

                            break;
                        case "Textbox":
                            string StrMin = "";
                            string StrMax = "";
                            string StrMemo = "";
                            float fTemp;
                            ToTextboxInputWinPara.fMax = 0;
                            ToTextboxInputWinPara.fMin = 0;
                            ToTextboxInputWinPara.StrMemo = "";
                            FrmTextBoxInput FTI= new FrmTextBoxInput();
                            DialogResult result= FTI.ShowDialog();
                            if(result == DialogResult.OK)
                            {
                                StrCurrentTextboxValue = FTI.StrReturn;
                            }
                            //在XML文档中处理
                            HandleNodeInfoAtXmlContent(StrCurrentFullPath, StrNodeType, StrCurrentTextboxValue);//在文档中找到该节点并处理
                            break;
                    }
                    treeView1.Invalidate();
                }

                if (hitTestInfo.Location == TreeViewHitTestLocations.Label)
                {
                    //点击标签
                    if (FocusNode.Tag != null)
                    {
                        switch (FocusNode.Tag.ToString())
                        {
                            case "Radio":
                                if (FocusNode.ImageKey == "RadioChecked")
                                {
                                    FocusNode.SelectedImageKey = "RadioChecked";
                                }
                                if (FocusNode.ImageKey == "Radio")
                                {
                                    FocusNode.SelectedImageKey = "Radio";
                                }
                                break;
                            case "Checkbox":
                                if (FocusNode.ImageKey == "Checkbox")
                                {
                                    FocusNode.SelectedImageKey = "Checkbox";
                                }
                                if (FocusNode.ImageKey == "CheckboxChecked")
                                {
                                    FocusNode.SelectedImageKey = "CheckboxChecked";
                                }
                                break;
                            default: break;
                        }
                        treeView1.Invalidate();
                    }
                }
            }
        }

  对应在XML文档中的处理函数:

        private void HandleNodeInfoAtXmlContent(string StrCurrentFullPath,string StrNodeType,string StrInputTextValue)
        {
            //在XML文档内容中处理节点信息,传入参数:StrCurrentFullPath是当前点击选择的节点全路径名称
            int FirstIndex = StrCurrentFullPath.IndexOf("\\");
            int LastIndex = StrCurrentFullPath.LastIndexOf("\\");
            string StrCurrentNodeName = StrCurrentFullPath.Substring(LastIndex + 1);
            //提取父节点的名称
            string[] SubStr= StrCurrentFullPath.Split("\\");
            string ParentStr = SubStr[SubStr.Length - 2];
            // 使用XPath表达式定位到具体的节点,点击的节点名称是caption值
            string XpathExpression="";
            XmlNode CalculateNode=null;//计算节点
            switch (StrNodeType)
            {
                case "Radio":
                    XpathExpression = "//" + ParentStr + "/option[@caption='" + StrCurrentNodeName + "']";
                    break;
                case "Checkbox":
                    XpathExpression = "//" + ParentStr + "/input[@caption='" + StrCurrentNodeName + "']";
                    break;
                case "Textbox":
                    XpathExpression = "//" + ParentStr + "/"+ StrCurrentNodeName;
                    break;
            }
            XmlNode BeSelectNode = XmlDoc.SelectSingleNode(XpathExpression);
            //得到父节点的全路径名
            string SParentPath = StrCurrentFullPath.Substring(0, LastIndex);
            //得到父节点
            XmlNode ParentNode = FindNodeAtXmlContentByFullPath(SParentPath);
            XmlNode TempNode = null;
            if (BeSelectNode != null && ParentNode!=null)
            {
                //根据节点类型处理本节点
                switch (StrNodeType)
                {
                    case "Radio":
                        string StrValue = "";
                        //找到该节点标识选中状态
                        foreach (XmlNode RadioChildNode in ParentNode.ChildNodes)
                        {
                            //单选,先将父节点下的子节点的select属性全部删除
                            if (RadioChildNode.Attributes["select"] != null)
                            {
                                RadioChildNode.Attributes.Remove(RadioChildNode.Attributes["select"]);
                            }
                            //找到子节点
                            if (RadioChildNode.Attributes["caption"].Value == StrCurrentNodeName)
                            {
                                TempNode = RadioChildNode;
                                StrValue = TempNode.Attributes["value"].Value;
                            }
                        }
                        //添加select属性
                        if (TempNode!=null)
                        {                                
                            if (HasAttribute(TempNode, "select"))
                            {
                                TempNode.Attributes["select"].Value = "true";
                            }
                            else
                            {
                                XmlAttribute RadioNodeAttr = XmlDoc.CreateAttribute("select");
                                RadioNodeAttr.Value = "true";
                                TempNode.Attributes.Append(RadioNodeAttr);
                            }
                        }
                        //为父节点的value属性赋值
                        ParentNode.Attributes["value"].Value = StrValue;
                        //寻找父节点的父节点
                        CalculateNode = ParentNode.ParentNode;
                        //计算
                        Autocalculate(CalculateNode);
                        break;
                    case "Checkbox":
                        Single TempSum = 0.0f;
                        //找到该节点标识状态,如果是选择则去掉,没有选择则加上,同时计算和
                        foreach (XmlNode CheckChildNode in ParentNode.ChildNodes)
                        {
                            if (CheckChildNode.Attributes["caption"].Value == StrCurrentNodeName)
                            {
                                TempNode = CheckChildNode;
                            }
                        }
                        //添加select属性
                        if (HasAttribute(TempNode, "select"))
                        {
                            if (TempNode.Attributes["select"].Value == "true")
                            {
                                //如果已经选择了,需要去掉选择
                                TempNode.Attributes.Remove(TempNode.Attributes["select"]);
                            }
                            else
                            {
                                TempNode.Attributes["select"].Value = "true";
                            }
                        }
                        else
                        {
                            XmlAttribute CheckSelectedAttr = XmlDoc.CreateAttribute("select");
                            CheckSelectedAttr.Value = "true";
                            TempNode.Attributes.Append(CheckSelectedAttr);
                        }

                        foreach (XmlNode CheckChildNode in ParentNode.ChildNodes)
                        {
                            if (HasAttribute(CheckChildNode, "select"))
                            {
                                TempSum += Convert.ToSingle(CheckChildNode.Attributes["value"].Value);
                            }
                        }
                        //为父节点的value属性赋值
                        ParentNode.Attributes["value"].Value = TempSum.ToString();
                        //寻找父节点的父节点
                        CalculateNode = ParentNode.ParentNode;
                        //计算
                        Autocalculate(CalculateNode);
                        break;
                    case "Textbox":
                        //找到该节点修改Value值
                        BeSelectNode.Attributes["value"].Value = StrInputTextValue;
                        //寻找本节点的父节点
                        CalculateNode = BeSelectNode.ParentNode;
                        //计算
                        Autocalculate(CalculateNode);
                        break;
                }
            }
            else
            {
                textBox1.Text += "提取属性值发生错误,没有找到对应节点或者属性值错误!" + Environment.NewLine;
            }
            
        }

  2、递归计算

        private void Autocalculate(XmlNode CalculateNode)
        {
            //在XML文档中,节点自动计算结果
            //CalculateResult MyCalcuteResult= new CalculateResult();
            float fSum = 0f;
            string StrID = "";
            string StrValue = "";
            string StrFormula = "";
            Boolean Continue = true;
            string StrFalse = "";
            //判断是否有子节点
            if (CalculateNode.HasChildNodes)
            {
                //有子节点需要看是否有计算公式,根据指定的节点进行自动计算
                if (HasAttribute(CalculateNode, "formula"))
                {
                    //如果节点有formula属性,则提取出计算公式。
                    StrFormula = GetAttrValue(CalculateNode, "formula");
                    //将所有子节点的值进行替换完成后再进行计算。
                    foreach (XmlNode MyNode in CalculateNode.ChildNodes)
                    {
                        if (HasAttribute(MyNode,"id"))
                        {
                            StrID = MyNode.Attributes["id"].Value;
                            StrValue = MyNode.Attributes["value"].Value;
                            if (StrValue.IsNullOrEmpty())
                            {
                                Continue = false;
                                StrFalse = $"{StrID}为空";
                                break;
                            }
                            else
                            {
                                //替换公式中的字符串,ID和值
                                StrFormula = StrFormula.Replace(StrID, StrValue);
                            }
                        }
                        else
                        {
                            Continue = false;
                        }
                    }
                    if (Continue)
                    {
                        //进行计算获得结果
                        fSum = GetFormulaResult(StrFormula);
                    }
                }
                else
                {
                    //没有formula属性,计算结果等于所有子节点的和。
                    foreach (XmlNode MyNode in CalculateNode.ChildNodes)
                    {
                        StrValue = MyNode.Attributes["value"].Value;
                        if (StrValue.IsNullOrEmpty())
                        {
                            Continue = false;
                            StrFalse = MyNode.Name +"的值为空";
                            break;
                        }
                        else
                        {
                            fSum += Convert.ToSingle(StrValue);
                        }
                    }
                }
                if (Continue)
                {
                    //修改本节点的Value属性
                    CalculateNode.Attributes["value"].Value = fSum.ToString();
                }
                CalculateNode = CalculateNode.ParentNode;
                //if (CalculateNode.NodeType == XmlNodeType.Document)
                if(CalculateNode==null)
                {
                    StrFalse = "没有了父节点";
                    Continue = false;
                }
                //是否继续计算
                if (Continue)
                {
                    Autocalculate(CalculateNode);
                }
                else
                {
                    textBox1.Text += StrFalse+Environment.NewLine;
                }
            }
        }

  这个问题看似简单,实际上也的确不难,就是有一点麻烦,需要耐心去解决细节问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1168368.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内网穿透实现远程访问,如何满足信息安全需求?

内网穿透技术是一种将内网服务映射到外网,从而实现远程访问的技术。它的出现为企业及个人带来了便利,但同时也带来了一定的安全风险。因此,确保内网穿透远程访问内网服务的安全性显得尤为重要。 贝锐旗下内网穿透兼动态域名解析品牌花生壳&am…

【漏洞库】XXL-JOB executor 未授权访问漏洞导致RCE

文章目录 漏洞描述漏洞编号漏洞评级影响版本漏洞复现- EXP 编写 漏洞挖掘修复建议 漏洞描述 XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。XXL-JOB分为adm…

TCP四次挥手过程解密:为什么不止三次挥手或更少次挥手?

🎬 江城开朗的豌豆:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 📝 个人网站 :《 江城开朗的豌豆🫛 》 ⛺️ 生活的理想,就是为了理想的生活 ! 目录 ⭐ 专栏简介 📘 文章引言 一、三…

使用Postman工具做接口测试 —— 断言与参数提取

引言 下面我会以登录为例,来讲如何利用postman提取上一个接口返回数据,并且放到当前接口来使用。 接口关联(参数提取) 下面以登录接口为例,讲一下postman如何使用参数提取,可以通过Fiddler工具对系统登录操作进行抓包分析&#…

linux报错汇总

1. linux 安装pytorch报错 CondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/linux-64/current_repodata.json> Elapsed: -An HTTP error occurred when trying to retrieve this URL. HTTP errors are o…

基于 Amazon EC2 和 Amazon Systems Manager Session Manager 的堡垒机的设计和自动化实现

文章目录 1. 背景2. 云上堡垒机设计2.1 安全设计2.2 高可用和弹性设计2.3 监控告警设计2.4 自动化部署设计2.4.1 堡垒机代码设计2.4.2 Session Manager 配置设计2.4.3 堡垒机 IAM 角色设计 3. 部署堡垒机3.1 堡垒机部署架构图3.2 堡垒机自动化部署 4. 堡垒机使用场景4.1 堡垒机…

[python 刷题] 2866 Beautiful Towers II

[python 刷题] 2866 Beautiful Towers II 题目如下&#xff1a; You are given a 0-indexed array maxHeights of n integers. You are tasked with building n towers in the coordinate line. The ith tower is built at coordinate i and has a height of heights[i]. A co…

Wi-Fi还可以做什么?柯南解释IOT应用

大会报告&#xff1a;无线人工智能技术正在改变世界 Wi-Fi还可以做什么&#xff1f;随着带宽的提升&#xff0c;无线终端可以识别出更多的多径&#xff0c;每条多径都可以视作一个虚拟传感器&#xff0c;以感知周边环境。基于此&#xff0c;越来越多的无线感知产品应运而生。20…

Leetcode1122. 数组的相对排序

Every day a Leetcode 题目来源&#xff1a;1122. 数组的相对排序 解法1&#xff1a;哈希 用集合 set 存储 arr2 中的元素。 遍历数组 arr1 &#xff0c;设当前元素为 num&#xff1a; 如果 num 在 set 中出现&#xff0c;用哈希表 hash 记录 num 和它出现的次数。否则&a…

【移远QuecPython】EC800M物联网开发板的内置GNSS定位的恶性BUG(目前没有完全的解决方案)

【移远QuecPython】EC800M物联网开发板的内置GNSS定位的恶性BUG&#xff08;目前没有完全的解决方案&#xff09; GNSS配置如下&#xff1a; 【移远QuecPython】EC800M物联网开发板的内置GNSS定位获取&#xff08;北斗、GPS和GNSS&#xff09; 测试视频&#xff08;包括BUG复…

大数据毕业设计选题推荐-热门旅游景点数据分析-Hadoop-Spark-Hive

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

第二章 Python字符串处理

系列文章目录 第一章 Python 基础知识 第二章 python 字符串处理 第三章 python 数据类型 第四章 python 运算符与流程控制 第五章 python 文件操作 第六章 python 函数 第七章 python 常用内建函数 第八章 python 类(面向对象编程) 第九章 python 异常处理 第十章 python 自定…

『亚马逊云科技产品测评』活动征文|搭建基础运维环境

授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 目录 1、什么是容器化部署 2、连接到控制台 3、安装docker 3.1 更新…

学习Opencv(蝴蝶书/C++)代码——1.macOS下安装OpenCV4.8.0和QT5.15(C++)

文章目录 1.前置条件-cmake和c2. opencv2.1 opencv安装2.2 opencv测试2.2.1 基本测试2.2.2 opencv里的自带测试图像 2.3 报错2.3.1 MacOSX10.15.sdk/usr/include/sys/cdefs.h:807:2: error: Unsupported architecture2.2.2 电脑上没有安装java(Unable to locate a Java Runtime…

TSINGSEE青犀智能分析网关人员徘徊AI算法应用场景概述

我们的AI边缘计算网关硬件 —— 智能分析网关目前有5个版本&#xff1a;V1、V2、V3、V4、V5&#xff0c;每个版本都能实现对监控视频的智能识别和分析&#xff0c;支持抓拍、记录、告警等&#xff0c;每个版本在算法模型及性能配置上略有不同。硬件可实现的AI检测包括&#xff…

HCIA数据通信——路由协议

数据通信——网络层&#xff08;OSPF基础特性&#xff09;_咕噜跳的博客-CSDN博客 数据通信——网络层&#xff08;RIP与BGP&#xff09;_咕噜跳的博客-CSDN博客 上述是之前写的理论知识部分&#xff0c;懒得在实验中再次提及了。这次做RIP协议以及OSPF协议。不过RIP协议不常用…

哪里能找到可以学习的前端实战项目?

前言 下面是我整理的一些关于GitHub上的前端相关的项目&#xff0c;希望对你有所帮助&#xff0c;整理不易&#xff0c;可以的话不要吝啬你的点赞喜欢收藏哈~ 废话少说&#xff0c;我们直接进入正题——> 实用工具向 1.Echarts Star&#xff1a;55.6k Echarts提供了大量…

【C++】异常【完整版】

目录 1.C语言传统的处理错误的方式 2. C异常概念 3. 异常的使用 3.1 异常的抛出和捕获 3.2 异常的重新抛出 3.3异常安全 3.4 异常规范 4.自定义异常体系 5.C标准库的异常体系 6.异常的优缺点 1.C语言传统的处理错误的方式 传统的错误处理机制&#xff1a; 1. 终止程序…

什么是OTP认证?OTP认证服务器有哪些应用场景?

OTP是一次性密码&#xff0c;即只能使用一次的密码。它基于专门的算法&#xff0c;每隔60秒生成一个不可预测的随机数字组合。这种密码的有效期仅在一次会话或交易过程中&#xff0c;因此不容易受到重放攻击。在计算器系统或其他数字设备上&#xff0c;OTP是一种只能使用一次的…

重定向-缓冲区

1.重定向 文件描述符对应的分配规则是什么? 尝试用这个代码 关闭0,1&#xff0c;2文件描述符&#xff0c;看看有什么现象&#xff1f;关闭哪个&#xff0c;你打开的文件fd应该就是哪个 结论&#xff1a; 从0下标开始&#xff0c;寻找最小的没有没使用的数组位置&#xff0c;它…