2014-01-28 62 views
2

我想將XML驗證添加到現有的Powershell腳本。我用C#編寫代碼作爲概念證明,但是當我移植到Powershell並使用相同的輸入文件時,我得到了不同的結果。我使用Powershell 3.0。Powershell XML驗證

我已經工作的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文件,其產生預期的「錯誤驗證XML文件」,從rSettings.ValidationEventHandler消息時與運行這段代碼。

我已經寫了相應的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:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
targetNamespace="http://www.test.com" 
xmlns="http://www.test.com" 
elementFormDefault="qualified" 
version="1.0.0"> 

    <xs:element name="root"> 
     <xs:complexType> 
     <xs:sequence> 
      <xs:element name="name" type="xs:string" /> 
      <xs:element name="age" type="xs:int" /> 
      <xs:element name="city" type="xs:string" /> 
     </xs:sequence> 
     <xs:attribute name="id" type="xs:int" /> 
     </xs:complexType> 
    </xs:element> 
</xs:schema> 

的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> 
+0

我認爲問題在於您在事件處理程序中使用了寫入輸出。如果您嘗試將其更改爲Write-Host(僅用於測試,而不是用於保存),則會看到它按預期寫入。 –

+0

@ robert.westerlund這工作 - 我添加了'寫輸出',因爲只是引用字符串不工作......我沒有嘗試第三個('寫主機')選項。爲什麼在這種情況下'Write-Output'沒有工作?由於管道中沒有別的東西,爲什麼當它在腳本塊中時,它會寫入Out-Default,正如[本文]中所述(http://stackoverflow.com/questions/8755497/which-shaould -i-use-write-host-write-output-or-consolewriteline) – TWReever

+0

寫輸出通常是您應該用來從某個方法獲取輸出的一個輸出(除非您的方法是用動詞Show命名的,根據我們正在討論的輸出類型,可以使用Write-Host cmdlet)或Write-Verbose,Write-Debug,Write-Warning或Write-Error。我不確定Write-Output如何處理事件(雖然還沒有閱讀或嘗試過),但是我可以想象它們是在不同的範圍內運行的(特別是因爲你真的不知道當一個事件處理程序將被調用)。 –

回答

0

在Powershell,事件處理程序以Jobs的形式運行。因此,它們的管道結果不會像在主腳本中的管道中那樣顯示在屏幕上。使用Receive-Job cmdlet可以執行正在執行的作業的管道結果。

由於Write-Output具有將對象顯示爲默認流出的效果,因此只有在從主腳本調用時纔會實際顯示到屏幕上。

來自Powershell Cook的這本書chapter,在解釋Powershell事件和作業方面做得不錯。