简体   繁体   中英

Combining Group-Object and ForEach-Object?

I'm developing a cmdlet called Merge-Xsd that can merge similar XML schemas. It takes a list of paths, loads the schemas, merges them, and produces an XMLDocument as output.

All schemas of a particular file name are considered "similar", and so what I'm doing is getting all of the child items in a particular directory structure, grouping them according to the file name, and then trying to pass them to my custom cmdlet.

Grouping them is easy:

$grouping = Get-ChildItem -Recurse -Filter *.xsd |
    Group-Object -Property Name -AsHashTable -AsString

However, processing them as part of the same pipeline is not. I've gotten as close as this:

$grouping.Keys |
    ForEach-Object { ($grouping[$_] |
        Select-Object -ExpandProperty FullName | Merge-Xsd).Save("C:\Out\$_") }

But what I'd really like to be able to do is use ForEach-Object directly after Group-Object to iterate over each group item, thus eliminating the need for the separate $grouping variable.

How can I use ForEach-Object to get the key/value pair while keeping each invocation of Merge-Xsd scoped to that particular key/value pair?

20150224 UPDATE:

The Merge-Xsd option set is extremely basic:

NAME
    Merge-Xsd

SYNTAX
    Merge-Xsd [-Path] <string[]>  [<CommonParameters>]

It is really just intended for throwing a bunch of files at it in one go and having them merged into a single output, which is an XmlDocument . (I modeled the output off of ConvertTo-Xml .)

I think you could just nest it like this:

Get-ChildItem -Recurse -Filter *.xsd |
    Group-Object -Property Name | 
        ForEach-Object { 
           ($_.Group.FullName | Merge-Xsd).Save("C:\Out\$($_.Name)")
        }

I don't have your cmdlet or files but in my limited testing this would work.

Some Explanation

I took out the -AsHash and -AsString parameters so we could deal directly with the group objects returned by Group-Object .

The $_.Group.FullName is more complex than it seems on first glance. $_ here refers to a single group object, since we're in a ForEach-Object . The group object contains a property called Name which is the name of the group, and a property called Group which is actually a collection of the the individual items within the group, so $_.Group is a collection.

From here, it would make sense to pipe that to ForEach-Object again, since each of the items in that collection will be a FileInfo object, and you want to get the FullName property to pass to Merge-Xsd .

Here we take advantage of some powershell magic. When you refer to $c.Property where $c is a collection of objects with a Property property, you get back a collection that consists of the property objects.

So $props = $c.Property is the same as:

$props = $c | ForEach-Object { $_.Property }

Knowing that, we can pipe $_.Group.FullName directly into Merge-Xsd to pass along all of the fullnames from all of the files in the group .

In that context, $_.Name still refers to the group object, so it's the name of the group, not the name of the file.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM