Powershell XML验证

Powershell XML验证,xml,validation,powershell,xsd,Xml,Validation,Powershell,Xsd,我正在尝试向现有Powershell脚本添加XML验证。我用C#编写代码作为概念证明,但当我移植到Powershell并使用相同的输入文件时,得到的结果不同。我正在使用Powershell 3.0 我使用的C代码是: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; using System.Xml.Schema; namespace S

我正在尝试向现有Powershell脚本添加XML验证。我用C#编写代码作为概念证明,但当我移植到Powershell并使用相同的输入文件时,得到的结果不同。我正在使用Powershell 3.0

我使用的C代码是:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Schema;

namespace SchemaTest
{
    class Program
    {
        const string SCHEMA_PATH = @"C:\Test\test_schema.xsd";
        const string XML_PATH = @"C:\Test\test.xml";

        static void Main(string[] args)
        {
            XmlReader schemaReader = XmlReader.Create(SCHEMA_PATH);
            XmlSchema schema = XmlSchema.Read(
                schemaReader,
                (Object sender, ValidationEventArgs e) =>
                {
                    Console.Out.WriteLine("Error reading schema file");
                }
            );
            schemaReader.Close();

            XmlReaderSettings rSettings = new XmlReaderSettings();
            rSettings.ValidationType = ValidationType.Schema;
            rSettings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
            rSettings.Schemas.Add(schema);
            rSettings.ValidationEventHandler += (Object sender, ValidationEventArgs e) =>
            {
                Console.Out.WriteLine("Error validating XML file");
            };

            XmlReader configReader = XmlReader.Create(XML_PATH, rSettings);

            XmlDocument doc = new XmlDocument();
            doc.Load(configReader);
            configReader.Close();

            Console.ReadKey(true);
        }
    }
}
我有一个简单的XSD模式和相应的(无效)XML文件,当使用此代码运行时,它会从
rSettings.ValidationEventHandler
生成预期的“错误验证XML文件”消息

我编写的相应Powershell代码如下所示:

$schemaReader = [System.Xml.XmlReader]::Create('C:\Test\test_schema.xsd')
[System.Xml.Schema.ValidationEventHandler]$schemaValidationHandler = { Write-Output "Error reading schema file" }
$schema = [System.Xml.Schema.XmlSchema]::Read($schemaReader, $schemaValidationHandler)
$schemaReader.Close()

$rSettings = New-Object -Type System.Xml.XmlReaderSettings
$rSettings.ValidationType = [System.Xml.ValidationType]::Schema
$rSettings.ValidationFlags = $rSettings.ValidationFlags -bor [System.Xml.Schema.XmlSchemaValidationFlags]::ReportValidationWarnings
$rSettings.Schemas.Add($schema)
Register-ObjectEvent -InputObject $rSettings -EventName ValidationEventHandler -Action { Write-Output 'Error validating XML file' }

$configReader = [System.Xml.XmlReader]::Create('C:\Test\test.xml', $rSettings)

$doc = New-Object -TypeName System.Xml.XmlDocument
$doc.Load($configReader)
$configReader.Close()
当我针对同一个XSD和XML文件运行此代码时,我没有得到预期的“错误验证XML文件”输出

为了进行故障排除,我注释掉了
Register ObjectEvent
调用,并验证了在调用
$doc.Load($configReader)
行时出现异常。这让我觉得注册事件处理程序有问题,但我似乎找不到替代方法

为了完整起见,下面是我用来测试这个的XSD和XML文件:

test_schema.xsd:


test.xml:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<root
 xmlns="http://www.test.com"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 id="1">
   <name>Joe</name>
<!--   Comment out <age> tags for testing
   <age>20</age>  
-->
   <city>New York City</city>
 </root>

乔
纽约市

在Powershell中,事件处理程序作为作业运行。因此,其管道的结果在屏幕上的显示方式与在主脚本的管道中的显示方式不同。使用cmdlet可以获得正在执行作业的管道的结果

由于
Write Output
具有将对象显示到默认扩展流的效果,因此它仅在从主脚本调用时才会实际显示到屏幕上


来自Powershell Cook一书的这篇文章在解释Powershell事件和作业方面做得很好。

我认为问题在于您在事件处理程序中使用了写输出。如果您尝试将其更改为写入主机(只是为了测试,而不是保存),您将看到它按照预期写入。@robert.westerlund有效-我添加了
写入输出
,因为只是引用字符串不起作用…我没有尝试第三个(
写入主机
)选项。在这种情况下,
写入输出
为什么不起作用?既然管道中没有其他内容,为什么当它位于脚本块中时不将其写入默认值,如中所述,写入输出通常是用于从方法获取输出的输出(除非您的方法使用动词Show命名,否则您可能根本不应该使用Write-Host cmdlet),或者写入Verbose、Write-Debug,写入警告或写入错误,具体取决于我们讨论的输出类型。虽然我不确定写输出是如何处理事件的(我还没有读过,也没有亲自尝试过),但我可以想象它们是在不同的范围内运行的(尤其是因为你真的不知道什么时候会调用eventhandler)。
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<root
 xmlns="http://www.test.com"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 id="1">
   <name>Joe</name>
<!--   Comment out <age> tags for testing
   <age>20</age>  
-->
   <city>New York City</city>
 </root>