16

Tôi đang sử dụng PowerShell v3 và Windows PowerShell ISE. Tôi có hàm sau đó hoạt động tốt:Thay đổi PowerShell trả về loại đối tượng

function Get-XmlNode([xml]$XmlDocument, [string]$NodePath, [string]$NamespaceURI = "", [string]$NodeSeparatorCharacter = '.') 
{ 
    # If a Namespace URI was not given, use the Xml document's default namespace. 
    if ([string]::IsNullOrEmpty($NamespaceURI)) { $NamespaceURI = $XmlDocument.DocumentElement.NamespaceURI } 

    # In order for SelectSingleNode() to actually work, we need to use the fully qualified node path along with an Xml Namespace Manager, so set them up. 
    [System.Xml.XmlNamespaceManager]$xmlNsManager = New-Object System.Xml.XmlNamespaceManager($XmlDocument.NameTable) 
    $xmlNsManager.AddNamespace("ns", $NamespaceURI) 

    [string]$fullyQualifiedNodePath = Get-FullyQualifiedXmlNodePath -NodePath $NodePath -NodeSeparatorCharacter $NodeSeparatorCharacter 

    # Try and get the node, then return it. Returns $null if the node was not found. 
    $node = $XmlDocument.SelectSingleNode($fullyQualifiedNodePath, $xmlNsManager) 
    return $node 
} 

Bây giờ, tôi sẽ tạo ra một vài chức năng tương tự, vì vậy tôi muốn phá vỡ 3 dòng đầu tiên ra thành một chức năng mới vì vậy mà tôi không cần phải sao chép -Dán họ ở khắp mọi nơi, vì vậy tôi đã làm điều này:

function Get-XmlNamespaceManager([xml]$XmlDocument, [string]$NamespaceURI = "") 
{ 
    # If a Namespace URI was not given, use the Xml document's default namespace. 
    if ([string]::IsNullOrEmpty($NamespaceURI)) { $NamespaceURI = $XmlDocument.DocumentElement.NamespaceURI } 

    # In order for SelectSingleNode() to actually work, we need to use the fully qualified node path along with an Xml Namespace Manager, so set them up. 
    [System.Xml.XmlNamespaceManager]$xmlNsManager = New-Object System.Xml.XmlNamespaceManager($XmlDocument.NameTable) 
    $xmlNsManager.AddNamespace("ns", $NamespaceURI) 
    return $xmlNsManager 
} 

function Get-XmlNode([xml]$XmlDocument, [string]$NodePath, [string]$NamespaceURI = "", [string]$NodeSeparatorCharacter = '.') 
{ 
    [System.Xml.XmlNamespaceManager]$xmlNsManager = Get-XmlNamespaceManager -XmlDocument $XmlDocument -NamespaceURI $NamespaceURI 
    [string]$fullyQualifiedNodePath = Get-FullyQualifiedXmlNodePath -NodePath $NodePath -NodeSeparatorCharacter $NodeSeparatorCharacter 

    # Try and get the node, then return it. Returns $null if the node was not found. 
    $node = $XmlDocument.SelectSingleNode($fullyQualifiedNodePath, $xmlNsManager) 
    return $node 
} 

vấn đề là khi "return $ xmlNsManager" thực hiện các lỗi sau được ném:

Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Xml.XmlNamespaceManager". 

vì vậy, mặc dù tôi đã đúc một cách rõ ràng các biến $ xmlNsManager của tôi là kiểu System.Xml.XmlNamespaceManager, khi nó được trả về từ hàm Get-XmlNamespaceManager, PowerShell đang chuyển đổi nó thành một mảng Object.

Nếu tôi không rõ ràng truyền giá trị được trả về từ hàm Get-XmlNamespaceManager đến System.Xml.XmlNamespaceManager, thì lỗi sau được ném từ hàm .SelectSingleNode() vì loại dữ liệu sai đang được chuyển vào tham số thứ 2 của hàm.

Cannot find an overload for "SelectSingleNode" and the argument count: "2". 

Vì vậy, vì một lý do nào đó PowerShell không duy trì kiểu dữ liệu của biến trả về. Tôi thực sự muốn có được điều này làm việc từ một chức năng để tôi không phải sao chép dán 3 dòng trên khắp nơi. Mọi đề xuất đều được đánh giá cao. Cảm ơn.

+2

Vì vậy, bạn đã làm gì với lệnh ghép ngắn 'Select-Xml' được tích hợp? Việc sử dụng các không gian tên với nó cũng đơn giản như việc truyền cho nó một tiền tố có thể bắt đầu để ánh xạ vùng tên, ví dụ: '$ xml | Select-Xml -XPath '// dns: foo' -namespace @ {dns = 'http: //schema.foo.org'} ' –

+0

Cảm ơn Keith, tôi thực sự đã không nghe nói về lệnh ghép ngắn Select-Xml. Tôi muốn bỏ qua không gian tên Xml tất cả cùng nhau như tôi không quan tâm về nó, nhưng tiếc là .SelectSingleNode() yêu cầu nó, như tôi thảo luận trong bài đăng blog của tôi (http://blog.danskingdom.com/powershell-functions- to-get-an-xml-nút-và-get-và-bộ-một-xml-yếu tố-giá trị-ngay cả khi-phần tử-không-không-đã tồn tại /).Việc sử dụng Select-Xml có giải quyết được vấn đề này không? – deadlydog

+1

'Select-Xml' chỉ gọi hoặc là' SelectSingleNode' hoặc 'SelectNodes' (của XmlDocument) dưới bìa, vì vậy nó vẫn nhạy cảm với các không gian tên XML, đó là lý do tại sao @Keith sử dụng tham số' -namespace'. –

Trả lời

25

Điều đang xảy ra là PowerShell đang chuyển đổi đối tượng trình quản lý không gian tên của bạn thành mảng chuỗi.

Tôi nghĩ rằng nó phải làm với bản chất của bộ sưu tập "unrolling" của PowerShell khi gửi các đối tượng xuống đường ống. Tôi nghĩ PowerShell sẽ làm điều này cho bất kỳ loại nào đang triển khai IEnumerable (có phương thức GetEnumerator).

Là một công việc xung quanh, bạn có thể sử dụng dấu phẩy để ngăn chặn hành vi này và gửi đối tượng dưới dạng toàn bộ bộ sưu tập.

function Get-XmlNamespaceManager([xml]$XmlDocument, [string]$NamespaceURI = "") 
{ 
    ... 
    $xmlNsManager.AddNamespace("ns", $NamespaceURI) 
    return ,$xmlNsManager 
} 
+0

Yup, XmlNamespaceManager triển khai IEnumerable để PowerShell xem đó là một chuỗi các mục. Sử dụng toán tử dấu phẩy là cách bạn khắc phục sự cố cụ thể này nhưng việc sử dụng 'return' thực sự không cần thiết trong trường hợp này (dòng cuối cùng của hàm nên không cần trả lại sớm). –

+0

Cảm ơn các bạn đã giải thích. Keith, tôi theo truyền thống là một lập trình viên C# và .Net, người chỉ mới vào PowerShell, vì vậy tôi vẫn có thói quen sử dụng trở lại; Tôi cũng thích rằng nó làm cho nó rõ ràng/rõ ràng những gì các chức năng đang trở lại. – deadlydog

+2

@deadlydog Một dấu hiệu khác (bên cạnh điều chưa được kiểm tra này) là bất kỳ thứ gì trả về giá trị không được đặt thành biến hoặc đường dẫn đến null sẽ được trả lại từ hàm của bạn, ví dụ: nếu bạn gọi XmlDocument (phương thức http://msdn.microsoft.com/en-us/library/system.xml.xmlnode.appendchild.aspx), nó sẽ trả về một đối tượng XmlNode sẽ được gửi cùng với đối tượng quản lý không gian tên trừ khi bạn ngăn chặn nó. –

1

Cụ thể hơn, những gì đang xảy ra ở đây là thói quen mã hóa của bạn gõ mạnh $ fullyQualifiedModePath đang cố gắng để biến kết quả của Nhận (mà là một danh sách các đối tượng) thành một chuỗi.

[chuỗi] $ foo

sẽ hạn chế $ foo biến để chỉ là một chuỗi, không có vấn đề gì trở lại. Trong trường hợp này, ràng buộc loại của bạn là những thứ phụ thuộc vào việc quay trở lại và làm cho nó trở thành Object []

Ngoài ra, hãy xem mã của bạn, tôi khuyên bạn nên sử dụng Select-Xml (được xây dựng trong phiên bản V2 trở lên) hơn là thực hiện nhiều thao tác unrolling XML bằng tay. Bạn có thể thực hiện truy vấn không gian tên trong Select-Xml với -Namespace @ {x = "..."}.

+1

Dòng '$ fullyQualifiedModePath' không phải là vấn đề mà anh gặp phải. Đây là cái này [[System.Xml.XmlNamespaceManager] $ xmlNsManager = ' –

Các vấn đề liên quan