PowerShell
XMLファイルの操作
サーチ…
XMLファイルへのアクセス
<!-- file.xml -->
<people>
<person id="101">
<name>Jon Lajoie</name>
<age>22</age>
</person>
<person id="102">
<name>Lord Gaben</name>
<age>65</age>
</person>
<person id="103">
<name>Gordon Freeman</name>
<age>29</age>
</person>
</people>
XMLファイルのロード
XMLファイルをロードするには、次のいずれかを使用できます。
# First Method
$xdoc = New-Object System.Xml.XmlDocument
$file = Resolve-Path(".\file.xml")
$xdoc.load($file)
# Second Method
[xml] $xdoc = Get-Content ".\file.xml"
# Third Method
$xdoc = [xml] (Get-Content ".\file.xml")
オブジェクトとしてのXMLへのアクセス
PS C:\> $xml = [xml](Get-Content file.xml)
PS C:\> $xml
PS C:\> $xml.people
person
--------
{Jon Lajoie, Lord Gaben, Gordon Freeman}
PS C:\> $xml.people.person
id name age
-- ---- ---
101 Jon Lajoie 22
102 Lord Gaben 65
103 Gordon Freeman 29
PS C:\> $xml.people.person[0].name
Jon Lajoie
PS C:\> $xml.people.person[1].age
65
PS C:\> $xml.people.person[2].id
103
XPathによるXMLへのアクセス
PS C:\> $xml = [xml](Get-Content file.xml)
PS C:\> $xml
PS C:\> $xml.SelectNodes("//people")
person
--------
{Jon Lajoie, Lord Gaben, Gordon Freeman}
PS C:\> $xml.SelectNodes("//people//person")
id name age
-- ---- ---
101 Jon Lajoie 22
102 Lord Gaben 65
103 Gordon Freeman 29
PS C:\> $xml.SelectSingleNode("people//person[1]//name")
Jon Lajoie
PS C:\> $xml.SelectSingleNode("people//person[2]//age")
65
PS C:\> $xml.SelectSingleNode("people//person[3]//@id")
103
XPathで名前空間を含むXMLにアクセスする
PS C:\> [xml]$xml = @"
<ns:people xmlns:ns="http://schemas.xmlsoap.org/soap/envelope/">
<ns:person id="101">
<ns:name>Jon Lajoie</ns:name>
</ns:person>
<ns:person id="102">
<ns:name>Lord Gaben</ns:name>
</ns:person>
<ns:person id="103">
<ns:name>Gordon Freeman</ns:name>
</ns:person>
</ns:people>
"@
PS C:\> $ns = new-object Xml.XmlNamespaceManager $xml.NameTable
PS C:\> $ns.AddNamespace("ns", $xml.DocumentElement.NamespaceURI)
PS C:\> $xml.SelectNodes("//ns:people/ns:person", $ns)
id name
-- ----
101 Jon Lajoie
102 Lord Gaben
103 Gordon Freeman
XmlWriter()を使用してXMLドキュメントを作成する
# Set The Formatting
$xmlsettings = New-Object System.Xml.XmlWriterSettings
$xmlsettings.Indent = $true
$xmlsettings.IndentChars = " "
# Set the File Name Create The Document
$XmlWriter = [System.XML.XmlWriter]::Create("C:\YourXML.xml", $xmlsettings)
# Write the XML Decleration and set the XSL
$xmlWriter.WriteStartDocument()
$xmlWriter.WriteProcessingInstruction("xml-stylesheet", "type='text/xsl' href='style.xsl'")
# Start the Root Element
$xmlWriter.WriteStartElement("Root")
$xmlWriter.WriteStartElement("Object") # <-- Start <Object>
$xmlWriter.WriteElementString("Property1","Value 1")
$xmlWriter.WriteElementString("Property2","Value 2")
$xmlWriter.WriteStartElement("SubObject") # <-- Start <SubObject>
$xmlWriter.WriteElementString("Property3","Value 3")
$xmlWriter.WriteEndElement() # <-- End <SubObject>
$xmlWriter.WriteEndElement() # <-- End <Object>
$xmlWriter.WriteEndElement() # <-- End <Root>
# End, Finalize and close the XML Document
$xmlWriter.WriteEndDocument()
$xmlWriter.Flush()
$xmlWriter.Close()
出力XMLファイル
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type='text/xsl' href='style.xsl'?>
<Root>
<Object>
<Property1>Value 1</Property1>
<Property2>Value 2</Property2>
<SubObject>
<Property3>Value 3</Property3>
</SubObject>
</Object>
</Root>
現在のXMLDocumentにXMLのスニペットを追加する
サンプルデータ
XMLドキュメント
まず、現在のディレクトリに「 books.xml 」というサンプルXMLドキュメントを定義しましょう。
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book>
<title>Of Mice And Men</title>
<author>John Steinbeck</author>
<pageCount>187</pageCount>
<publishers>
<publisher>
<isbn>978-88-58702-15-4</isbn>
<name>Pascal Covici</name>
<year>1937</year>
<binding>Hardcover</binding>
<first>true</first>
</publisher>
<publisher>
<isbn>978-05-82461-46-8</isbn>
<name>Longman</name>
<year>2009</year>
<binding>Hardcover</binding>
</publisher>
</publishers>
<characters>
<character name="Lennie Small" />
<character name="Curley's Wife" />
<character name="George Milton" />
<character name="Curley" />
</characters>
<film>True</film>
</book>
<book>
<title>The Hunt for Red October</title>
<author>Tom Clancy</author>
<pageCount>387</pageCount>
<publishers>
<publisher>
<isbn>978-08-70212-85-7</isbn>
<name>Naval Institute Press</name>
<year>1984</year>
<binding>Hardcover</binding>
<first>true</first>
</publisher>
<publisher>
<isbn>978-04-25083-83-3</isbn>
<name>Berkley</name>
<year>1986</year>
<binding>Paperback</binding>
</publisher>
<publisher>
<isbn>978-08-08587-35-4</isbn>
<name>Penguin Putnam</name>
<year>2010</year>
<binding>Paperback</binding>
</publisher>
</publishers>
<characters>
<character name="Marko Alexadrovich Ramius" />
<character name="Jack Ryan" />
<character name="Admiral Greer" />
<character name="Bart Mancuso" />
<character name="Vasily Borodin" />
</characters>
<film>True</film>
</book>
</books>
新しいデータ
私たちがしたいことは、この文書にいくつかの新しい本を追加することです。Tom ClancyのPatriot Games (はい、私はClancyの作品のファンです^^)とSci-Fiのお気に入り: Hitchhiker's Galaxy Douglas Adamsの主な理由は、Zaphod Beeblebroxが読むのが楽しいからです。
何とか新しい書籍のデータを取得し、PSCustomObjectsのリストとして保存しました。
$newBooks = @(
[PSCustomObject] @{
"Title" = "Patriot Games";
"Author" = "Tom Clancy";
"PageCount" = 540;
"Publishers" = @(
[PSCustomObject] @{
"ISBN" = "978-0-39-913241-4";
"Year" = "1987";
"First" = $True;
"Name" = "Putnam";
"Binding" = "Hardcover";
}
);
"Characters" = @(
"Jack Ryan", "Prince of Wales", "Princess of Wales",
"Robby Jackson", "Cathy Ryan", "Sean Patrick Miller"
);
"film" = $True;
},
[PSCustomObject] @{
"Title" = "The Hitchhiker's Guide to the Galaxy";
"Author" = "Douglas Adams";
"PageCount" = 216;
"Publishers" = @(
[PSCustomObject] @{
"ISBN" = "978-0-33-025864-7";
"Year" = "1979";
"First" = $True;
"Name" = "Pan Books";
"Binding" = "Hardcover";
}
);
"Characters" = @(
"Arthur Dent", "Marvin", "Zaphod Beeblebrox", "Ford Prefect",
"Trillian", "Slartibartfast", "Dirk Gently"
);
"film" = $True;
}
);
テンプレート
新しいデータを入れるために、いくつかのスケルトンXML構造を定義する必要があります。基本的には、データの各リストに対してスケルトン/テンプレートを作成する必要があります。この例では、ブック、文字、パブリッシャーのテンプレートが必要です。これを使用して、 filmタグの値など、いくつかのデフォルト値を定義することもできます。
$t_book = [xml] @'
<book>
<title />
<author />
<pageCount />
<publishers />
<characters />
<film>False</film>
</book>
'@;
$t_publisher = [xml] @'
<publisher>
<isbn/>
<name/>
<year/>
<binding/>
<first>false</first>
</publisher>
'@;
$t_character = [xml] @'
<character name="" />
'@;
私たちはセットアップを終えました。
新しいデータを追加する
今度は、サンプルデータをすべてセットアップしたので、カスタムオブジェクトをXMLドキュメントオブジェクトに追加しましょう。
# Read the xml document
$xml = [xml] Get-Content .\books.xml;
# Let's show a list of titles to see what we've got currently:
$xml.books.book | Select Title, Author, @{N="ISBN";E={If ( $_.Publishers.Publisher.Count ) { $_.Publishers.publisher[0].ISBN} Else { $_.Publishers.publisher.isbn}}};;
# Outputs:
# title author ISBN
# ----- ------ ----
# Of Mice And Men John Steinbeck 978-88-58702-15-4
# The Hunt for Red October Tom Clancy 978-08-70212-85-7
# Let's show our new books as well:
$newBooks | Select Title, Author, @{N="ISBN";E={$_.Publishers[0].ISBN}};
# Outputs:
# Title Author ISBN
# ----- ------ ----
# Patriot Games Tom Clancy 978-0-39-913241-4
# The Hitchhiker's Guide to the Galaxy Douglas Adams 978-0-33-025864-7
# Now to merge the two:
ForEach ( $book in $newBooks ) {
$root = $xml.SelectSingleNode("/books");
# Add the template for a book as a new node to the root element
[void]$root.AppendChild($xml.ImportNode($t_book.book, $true));
# Select the new child element
$newElement = $root.SelectSingleNode("book[last()]");
# Update the parameters of that new element to match our current new book data
$newElement.title = [String]$book.Title;
$newElement.author = [String]$book.Author;
$newElement.pageCount = [String]$book.PageCount;
$newElement.film = [String]$book.Film;
# Iterate through the properties that are Children of our new Element:
ForEach ( $publisher in $book.Publishers ) {
# Create the new child publisher element
# Note the use of "SelectSingleNode" here, this allows the use of the "AppendChild" method as it returns
# a XmlElement type object instead of the $Null data that is currently stored in that leaf of the
# XML document tree
[void]$newElement.SelectSingleNode("publishers").AppendChild($xml.ImportNode($t_publisher.publisher, $true));
# Update the attribute and text values of our new XML Element to match our new data
$newPublisherElement = $newElement.SelectSingleNode("publishers/publisher[last()]");
$newPublisherElement.year = [String]$publisher.Year;
$newPublisherElement.name = [String]$publisher.Name;
$newPublisherElement.binding = [String]$publisher.Binding;
$newPublisherElement.isbn = [String]$publisher.ISBN;
If ( $publisher.first ) {
$newPublisherElement.first = "True";
}
}
ForEach ( $character in $book.Characters ) {
# Select the characters xml element
$charactersElement = $newElement.SelectSingleNode("characters");
# Add a new character child element
[void]$charactersElement.AppendChild($xml.ImportNode($t_character.character, $true));
# Select the new characters/character element
$characterElement = $charactersElement.SelectSingleNode("character[last()]");
# Update the attribute and text values to match our new data
$characterElement.name = [String]$character;
}
}
# Check out the new XML:
$xml.books.book | Select Title, Author, @{N="ISBN";E={If ( $_.Publishers.Publisher.Count ) { $_.Publishers.publisher[0].ISBN} Else { $_.Publishers.publisher.isbn}}};
# Outputs:
# title author ISBN
# ----- ------ ----
# Of Mice And Men John Steinbeck 978-88-58702-15-4
# The Hunt for Red October Tom Clancy 978-08-70212-85-7
# Patriot Games Tom Clancy 978-0-39-913241-4
# The Hitchhiker's Guide to the Galaxy Douglas Adams 978-0-33-025864-7
XMLをディスク、スクリーン、ウェブ、またはどこにでも書くことができるようになりました!
利益
これは誰のための手続きではないかもしれませんが、 [void]$xml.SelectSingleNode("/complicated/xpath/goes[here]").AppendChild($xml.CreateElement("newElementName")束を避けるためにそれを見つけました[void]$xml.SelectSingleNode("/complicated/xpath/goes[here]").AppendChild($xml.CreateElement("newElementName") $xml.SelectSingleNode("/complicated/xpath/goes/here/newElementName") = $textValue
私は、この例で詳述されているメソッドは、より洗練されており、通常の人間のために解析するのが簡単だと思います。
改善
別のテンプレートとして各セクションを分割するのではなく、子を持つ要素を含むようにテンプレートを変更することができます。あなたは、リストをループするときに前の要素を複製するように気を配らなければなりません。