
示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载本文基于 Windows-universal-samples 仓库中的 XmlDocument 样例系统讲解 Windows Runtime 中Windows.Data.Xml.Dom与Windows.Data.Xml.Xsl两个命名空间的常见使用场景从异步加载 XML、构建 CDATA 节、XPath 查询与 DOM 树修改到通过XmlLoadSettings配置 DTD 安全策略再到使用 XSLT 将 XML 转换为 HTML 或新文档。读完本文你将掌握一套完整的、可直接复制到 C# UWP 项目中的 WinRT XML 处理方案并了解每个关键 API 在样例源码中的真实调用方式。样例总览与工程结构该样例面向Windows 10的 UWP 应用用 C# 演示了五个典型场景源码见 Samples/XmlDocument/cs 目录场景标题导航栏核心 API对应文件1Build New RSSXmlDocument.LoadFromFileAsync、CreateCDataSectionScenario1_BuildNewRss.xaml.cs2DOM Load/SaveSelectNodesXPath、SaveToFileAsyncScenario2_MarkHotProducts.xaml.cs3Set Load SettingsXmlLoadSettings.ProhibitDtd/ResolveExternalsScenario3_XmlLoading.xaml.cs4XPath QuerySelectNodes、SelectSingleNodeScenario4_GiftDispatch.xaml.cs5XSLT TransformationXsltProcessor.TransformToString/TransformToDocumentScenario5_XSLTTransform.xaml.cs这五个场景在 SampleConfiguration.cs 中注册为导航项ListScenario scenarios new ListScenario { new Scenario() { Title Build New RSS, ClassType typeof(Xml.BuildNewRss) }, new Scenario() { Title DOM Load/Save, ClassType typeof(Xml.MarkHotProducts) }, new Scenario() { Title Set Load Settings, ClassType typeof(Xml.XmlLoading) }, new Scenario() { Title XPath Query, ClassType typeof(Xml.GiftDispatch) }, new Scenario() { Title XSLT Transformation, ClassType typeof(Xml.XSLTTransform) } };所有场景共用一个静态辅助方法Scenario.LoadXmlFile定义于 SampleConfiguration.cs它从 UWP 包的安装目录Package.Current.InstalledLocation中定位数据文件并以固定安全设置加载public static async TaskXmlDocument LoadXmlFile(String folder, String file) { StorageFolder storageFolder await Package.Current.InstalledLocation.GetFolderAsync(folder); StorageFile storageFile await storageFolder.GetFileAsync(file); XmlLoadSettings loadSettings new XmlLoadSettings(); loadSettings.ProhibitDtd false; loadSettings.ResolveExternals false; return await XmlDocument.LoadFromFileAsync(storageFile, loadSettings); }从源码结构看每个场景的初始数据都是打包进应用的静态资源分别位于 buildRss/rssTemplate.xml、markHotProducts/products.xml、loadExternaldtd/xmlWithExternaldtd.xml、giftDispatch/employees.xml 和 xsltTransform/ 目录。这一点对理解 UWP 的文件访问模型很关键包内文件通过InstalledLocation只读访问而用户可写文件则写入ApplicationData.Current.LocalFolder。场景 1异步加载 RSS 模板并插入 CDATA 节场景 1 演示了两个基础能力XmlDocument.LoadFromFileAsync的异步文件加载以及用CreateCDataSection向 DOM 树中写入一段不被解析的原始文本。页面初始化时加载 RSS 模板 rssTemplate.xml?xml version1.0 encodingUTF-8 ? rss version2.0 channel titlePay Less For More/title linkhttp://paylessformore/link descriptionPay Less For More Homepage/description content /content /channel /rss注意模板中预留了空的content元素。用户在输入框中填写 RSS 内容并点击按钮后核心处理逻辑如下摘自 Scenario1_BuildNewRss.xaml.csvar doc new XmlDocument(); scenario1OriginalData.Document.GetText(TextGetOptions.None, out xml); doc.LoadXml(xml); // 从字符串构建 DOM 树 // 创建 CDATA 节并挂到 content 元素下 var cdata doc.CreateCDataSection(rss); var element doc.GetElementsByTagName(content).Item(0); element.AppendChild(cdata); Scenario.RichEditBoxSetMsg(scenario1Result, doc.GetXml(), true);这段代码展示了一个常见的“读取—修改—序列化”流程LoadXml(xml)把字符串解析为 DOM 文档与异步的LoadFromFileAsync相对这里是内存加载CreateCDataSection(rss)生成![CDATA[...]]节点保证插入的内容不会被当作 XML 标记解析——对于嵌入脚本、正则表达式等含、字符的文本这是正确做法GetElementsByTagName(content).Item(0)定位目标元素AppendChild将 CDATA 节点作为子节点挂入最后GetXml()把修改后的整棵树序列化回字符串显示。如果输入为空样例会以红色文本提示 “Please type in RSS content in the [RSS Content] box firstly.”这是样例中统一的错误反馈方式由 SampleConfiguration.cs 中的RichEditBoxSetText/RichEditBoxSetError辅助方法实现。场景 2XPath 定位节点、修改属性并保存文件场景 2 的业务是“标记热销商品”当商品的十天内销量Sell10day超过在店库存InStore时将其hot属性置为 1并可把结果保存到磁盘。初始数据 products.xml 结构如下products product idDVD-001 titleToy story 3 hot0 price12.99/price InStore35/InStore Sell10day33/Sell10day /product product idDVD-002 titleThe Blind Side hot0 price15.99/price InStore12/InStore Sell10day48/Sell10day /product /products“Mark Hot Products” 按钮的处理函数Scenario2_MarkHotProducts.xaml.cs用一条 XPath 谓词完成筛选与修改var xpath /products/product[Sell10dayInStore]/hot; var hotAttributes doc.SelectNodes(xpath); for (uint index 0; index hotAttributes.Length; index) { hotAttributes.Item(index).NodeValue 1; }几个值得注意的细节XPath 谓词product[Sell10dayInStore]直接对同元素下的两个子节点做数值比较只有 DVD-00248 12满足条件表达式以/hot结尾SelectNodes返回的是XmlAttribute节点集合因此通过NodeValue 1修改属性值而不是SetAttribute修改完成后doc.GetXml()输出整个更新后的文档同时把 “Save” 按钮从禁用变为可用。“Save” 按钮则演示了SaveToFileAsync的用法Scenario2_MarkHotProducts.xaml.csvar file await ApplicationData.Current.LocalFolder .CreateFileAsync(HotProducts.xml, CreationCollisionOption.GenerateUniqueName); await doc.SaveToFileAsync(file);这里体现了 UWP 的存储模型写入目标是应用本地文件夹ApplicationData.Current.LocalFolder冲突时通过CreationCollisionOption.GenerateUniqueName自动改名避免覆盖上一次的结果。场景 3XmlLoadSettings 的 DTD 安全设置这是样例中安全性价值最高的场景。加载来自外部、不可信来源的 XML 时prohibitDTD与resolveExternals两项设置决定了解析器的安全边界ProhibitDtdprohibitDTD为true时禁止 XML 文件使用 DTD。README 明确指出了动机——大量 DTD 实体引用可能导致应用在加载和解析 XML 文件时长时间无响应即常见的 “billion laughs” 类攻击ResolveExternalsresolveExternals决定解析过程中是否解析外部引用例如外部 DTD 定义。样例数据 xmlWithExternaldtd.xml 故意包含一个 DOCTYPE 声明指向同目录下的外部 DTD 文件 dtd.txt?xml version1.0 standaloneno? !DOCTYPE dtds SYSTEM dtd.txt dtds dtd nameXML DTD sample1/name urlhttp://www.microsoft.com/url /dtd ... /dtds!ELEMENT dtds (dtd) !ELEMENT dtd (name,url) !ELEMENT name (#PCDATA) !ELEMENT url (#PCDATA)界面上提供三个单选按钮对应 Scenario3_XmlLoading.xaml.cs 中的三种设置组合选项ProhibitDtdResolveExternals预期行为RB1truefalse解析抛异常样例 XML 含 DTD界面显示 “Error: DTD is prohibited”RB2falsefalseDTD 声明保留但不解析外部引用RB3falsetrue解析并解析外部 DTD见下方路径替换技巧该场景同时演示了两种加载入口二者共用同一套XmlLoadSettings按文件加载LoadFromFileAsyncvar loadSettings new XmlLoadSettings(); // ... 按单选项设置 ProhibitDtd / ResolveExternals ... var folder await Package.Current.InstalledLocation.GetFolderAsync(loadExternaldtd); var file await folder.GetFileAsync(xmlWithExternaldtd.xml); var doc await XmlDocument.LoadFromFileAsync(file, loadSettings);按缓冲区加载LoadXmlFromBuffer先把 XML 字符串写入DataWriter用DetachBuffer取出IBuffer再调用doc.LoadXmlFromBuffer(ibuffer, loadSettings)。从源码中可以看到一个针对 UWP 沙箱的实用技巧Scenario3_XmlLoading.xaml.cs当ResolveExternals true且ProhibitDtd false时外部 DTD 的相对路径dtd.txt会被替换为包安装目录下的完整路径if (loadSettings.ResolveExternals true loadSettings.ProhibitDtd false) { StorageFolder storageFolder await Package.Current.InstalledLocation.GetFolderAsync(loadExternaldtd); String dtdPath storageFolder.Path \\dtd.txt; xml xml.Replace(dtd.txt, dtdPath); }原因在于缓冲方式加载时解析器没有默认的文档位置上下文必须提供可解析的绝对路径。另外样例在ProhibitDtd true时对异常做了“预期内”处理——捕获后仅提示 “Error: DTD is prohibited”而不是当作程序故障这为调用方提供了一个处理已知安全拒绝的良好示范。场景 4用 XPath 谓词批量筛选节点场景 4“Show Anniversary Gift”演示如何根据工龄区间为员工匹配年礼本质是三次带数值谓词的SelectNodes查询 两次SelectSingleNode取值。员工数据 employees.xmlemployees employee nameMicheal Jackson/name departmentCustomer Support/department startyear2004/startyear /employee employee nameAnni Wang/name departmentBusiness Partner/department startyear2009/startyear /employee employee nameSail Young/name departmentConsulting/department startyear2000/startyear /employee /employees筛选逻辑Scenario4_GiftDispatch.xaml.csvar thisYear 2012; // 固定为 2012保证三个礼品档位都能被演示覆盖 var previousOneYear thisYear - 1; // 2011 var previousFiveYear thisYear - 5; // 2007 var previousTenYear thisYear - 10;// 2002 var xpathArray new String[3]; // 1~4 年入职年份在 (2007, 2011] 内 xpathArray[0] descendant::employee[startyear previousOneYear and startyear previousFiveYear ]; // 5~9 年入职年份在 (2002, 2007] 内 xpathArray[1] descendant::employee[startyear previousFiveYear and startyear previousTenYear ]; // 10 年及以上入职年份 2002 xpathArray[2] descendant::employee[startyear previousTenYear ]; var Gifts new String[3] { Gift Card, XBOX, Windows Phone };对每条 XPath 执行doc.SelectNodes(xpath)得到节点集合再对每个员工节点用SelectSingleNode(descendant::name)与SelectSingleNode(descendant::department)取出姓名和部门通过FirstChild.NodeValue读取文本内容最终按[姓名]/[部门]/[礼品]的格式输出。从源码可以读出两处细节其一年份基准固定为 2012 而非DateTime.Now.Year注释解释原因是“保证所有礼品档位都能被发放演示数据恰好覆盖”其二以固定基准 2012 计算样例数据中的三位员工分别命中 Gift Card2004 年、2009 年入职与 Windows Phone2000 年入职两档XBOX 档在该数据下不会命中。场景 5用 XSLT 将 XML 转换为 HTML 或新文档场景 5 使用Windows.Data.Xml.Xsl命名空间中的XsltProcessor类演示把源 XML 按 XSL 样式表转换为 HTML 页面字符串或转换为新的XmlDocument两个方向。初始化时Scenario5_XSLTTransform.xaml.cs分别从 xsltTransform/ 目录异步加载源 XML xmlContent.xml 与样式表 xslContent.xml 到两个可编辑输入区因此运行时可以直接修改两者来观察转换结果的差异。源 XML带命名空间library xmlnshttp://www.microsoft.com book chapter/chapter chapter section paragraph ab1/paragraph paragraph ab2/paragraph /section /chapter /book /libraryXSL 样式表核心是一个匹配根节点的模板通过xsl:for-each遍历深路径m:library/m:book/m:chapter/m:section/m:paragraph其中m前缀绑定到http://www.microsoft.com命名空间把每个段落及其属性a输出为 HTML 表格行。注意样式表中的模板路径必须与源文档的命名空间前缀声明配套否则for-each选不中节点——这也是 XSLT 处理带命名空间文档时的典型坑。“TransformToString” 按钮的处理Scenario5_XSLTTransform.xaml.csdoc new XmlDocument(); doc.LoadXml(xml); xsltDoc new XmlDocument(); xsltDoc.LoadXml(xslt); // 按样式表声明把 XML 变换为 HTML 字符串 var xsltProcessor new XsltProcessor(xsltDoc); String transformedStr xsltProcessor.TransformToString(doc);“TransformToDocument” 按钮则把结果作为XmlDocument拿到手并落盘Scenario5_XSLTTransform.xaml.csvar xsltProcessor new XsltProcessor(xsltDoc); XmlDocument transformedDocument xsltProcessor.TransformToDocument(doc); StorageFolder storageFolder ApplicationData.Current.LocalFolder; StorageFile xmlFile await storageFolder.CreateFileAsync(transformed.xml, CreationCollisionOption.ReplaceExisting); await transformedDocument.SaveToFileAsync(xmlFile);对比场景 2 的GenerateUniqueName这里选择ReplaceExisting即每次运行都覆盖同一个transformed.xml两种CreationCollisionOption的差异正好在这两个场景中得到了对照。此外该场景把“源 XML 无效”“XSL 无效”“变换失败”分成三段try/catch分别把对应的输入框文字标红并给出具体错误消息是处理多输入依赖型操作时值得借鉴的异常组织方式。构建与运行前提条件为Windows 10与 Microsoft Visual StudioUWP 开发工作负载。按照 Samples/XmlDocument/README.md 中的步骤如果下载的是样例集合 ZIP务必解压整个归档本样例依赖根目录下的 LICENSE 等共享内容而不仅解压本样例文件夹打开 Visual Studio选择文件 打开 项目/解决方案进入解压目录的Samples/XmlDocument/cs子目录双击 XmlDocument.sln 加载解决方案本样例仅提供 C# 版本工程文件为 XmlDocument.csproj按CtrlShiftB或选择生成 生成解决方案完成构建。部署与运行仅部署选择生成 部署解决方案调试并运行按F5或选择调试 开始调试不调试直接运行按CtrlF5调试 开始执行但不调试。运行后从左侧导航栏选择五个场景之一即可分别验证上述各 API 的行为。进一步参考WinRT 类型参考Windows.Data.Xml.Dom.XmlDocument与Windows.Data.Xml.Xsl.XsltProcessor样例 README 的 “Related topics” 指向官方文档仓库中另有已归档的 JavaScript 版本实现可对比不同语言下的 API 形态archived/XmlDocument/README.md本样例同仓库的 Samples/XmlLite/README.md 演示了更底层的XmlReader/XmlWriter解析器适合处理大型 XML 时与本文的 DOM 方案作选型对比。从整体结构看这五个场景覆盖了 UWP 中处理 XML 的完整链路——加载文件/字符串/缓冲区→ 查询XPath/SelectNodes→ 修改节点/属性→ 安全控制XmlLoadSettings→ 输出字符串/文档/文件/HTML每个场景的代码量都很小且相互独立是阅读 WinRT XML API 的合适入口。赞分享示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载相关推荐UWP 中 ListView 与 GridView 的实战指南基于 Windows-universal-samples XamlListView 示例的源码解析UWP 中 ListView 与 GridView 的实战指南基于 Windows universal samples XamlListView 示例的源码解示例工程SleeperXmacOS系统级电源管理框架的技术实现与应用SleeperXmacOS系统级电源管理框架的技术实现与应用 在macOS生态系统中电源管理一直是一个复杂而关键的技术领域。对于需要在特定场景下保持系统活跃示例工程UWP 多窗口实战基于 AppWindow 的 Windows-universal-samples 二次窗口开发指南UWP 多窗口实战基于 AppWindow 的 Windows universal samples 二次窗口开发指南 导读 本指南以 Windows univ示例工程上一篇Windows右键菜单管理终极指南让右键菜单焕然一新的ContextMenuManager下一篇NVIDIA Profile Inspector DLSS功能异常修复指南3步快速解决未知设置问题创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考