将 XML 的 snippits 添加到当前的 XMLDocument
样本数据
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>
新数据
我们想要做的是在本文档中添加一些新书,让我们说汤姆克兰西的爱国者游戏 (是的,我是克兰西作品的粉丝^ __ ^)和科幻爱好者: 银河系漫游指南道格拉斯亚当斯主要是因为 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 .ooks.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 写入磁盘,屏幕,Web 或任何地方!
利润
虽然这可能不是每个人的程序,我发现它可以帮助避免一大堆 [void]$xml.SelectSingleNode("/complicated/xpath/goes[here]").AppendChild($xml.CreateElement("newElementName")
然后 $xml.SelectSingleNode("/complicated/xpath/goes/here/newElementName") = $textValue
我认为示例中详述的方法更清晰,更容易解析普通人。
改进
可以更改模板以包含具有子项的元素,而不是将每个部分作为单独的模板分解。循环遍历列表时,你只需要注意克隆前一个元素。