如何用C#获取XML二级节点内容并转换PowerShell函数为C#
解决C# PowerShell二进制模块获取XML二级节点的问题
我明白你现在的需求:要在C#写的PowerShell二进制模块里,实现和Invoke-Transform完全一样的功能——解析XML中<m:properties>下的属性名和值,同时解决节点导航和类型转换的问题。下面给你一步步梳理解决方案:
先明确核心需求对应的逻辑
你的PowerShell函数本质是:遍历输入的XmlElement数组,逐个导航到content -> m:properties节点,然后把properties下的每个子节点(去掉命名空间前缀)作为属性名,节点文本作为值,输出成PowerShell可识别的自定义对象。
C#实现完整代码示例
首先要注意XML命名空间的处理(因为m:前缀对应特定的命名空间URI,必须映射才能找到节点),然后用正确的方式转换节点类型、构建输出对象:
using System; using System.Management.Automation; using System.Xml; using System.Linq; namespace MyPowerShellModule { [Cmdlet(VerbsLifecycle.Invoke, "Transform")] [OutputType(typeof(PSObject))] public class InvokeTransformCommand : Cmdlet { [Parameter(Mandatory = true, ValueFromPipeline = true)] public XmlElement[] Records { get; set; } protected override void ProcessRecord() { // 替换成你实际XML中m:前缀对应的命名空间URI(从xmlns:m属性获取) XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable()); nsManager.AddNamespace("m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"); foreach (XmlElement record in Records) { // 模拟PowerShell中的 ($record).content 导航 XmlElement contentNode = record.SelectSingleNode("./content") as XmlElement; if (contentNode == null) { WriteWarning("当前record节点未找到content子节点"); continue; } // 模拟PowerShell中的 ($record).content.properties 导航,这里必须用命名空间管理器 XmlElement propertiesNode = contentNode.SelectSingleNode("./m:properties", nsManager) as XmlElement; if (propertiesNode == null) { WriteWarning("content节点下未找到m:properties子节点"); continue; } // 构建和PowerShell PSCustomObject等价的输出对象 PSObject outputObj = new PSObject(); // 遍历properties下的所有XmlElement子节点(过滤掉文本、注释等非元素节点) foreach (XmlElement propNode in propertiesNode.ChildNodes.Cast<XmlNode>().Where(n => n is XmlElement)) { // 用LocalName去掉命名空间前缀(比如m:Id变成Id) string propName = propNode.LocalName; string propValue = propNode.InnerText; // 给输出对象添加属性 outputObj.Properties.Add(new PSNoteProperty(propName, propValue)); } // 输出结果,PowerShell中会像原生对象一样处理 WriteObject(outputObj); } } } }
关键问题的解决说明
- 命名空间处理:带前缀的XML节点(比如
m:properties)必须通过XmlNamespaceManager映射对应的URI才能被找到,你需要把代码中的URI替换成你实际XML里的xmlns:m属性值。 - XmlNode转XmlElement:
- 用
as XmlElement做安全转换,避免强制转换抛出异常; - 用
Cast<XmlNode>().Where(n => n is XmlElement)过滤掉非元素类型的节点(比如空白文本节点),和PowerShell中ChildNodes | Where-Object { $_ -is [XmlElement] }的逻辑一致。
- 用
- 模拟PowerShell链式访问:
record.SelectSingleNode("./content")对应$record.content;contentNode.SelectSingleNode("./m:properties", nsManager)对应$record.content.properties,完全还原PowerShell的节点导航逻辑。
- 输出对象匹配:用
PSObject配合PSNoteProperty构建的对象,在PowerShell中可以直接用Select-Object、Format-Table等命令处理,和原生PSCustomObject效果一致。
测试验证
编译这个模块导入PowerShell后,执行类似以下命令就能得到和Invoke-Transform一样的结果:
$xml = [xml](Get-Content .\your-example.xml) $xml.root.record | Invoke-Transform
内容的提问来源于stack exchange,提问作者user14132058
相关产品推荐
相关产品推荐

