質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
PowerShell

Windows PowerShellはコマンドラインインターフェースであり、システム管理を含むWindowsタスク自動化のためのスクリプト言語です。

Q&A

解決済

2回答

4838閲覧

PowerShell で XML の 要素 の 追加 をしたい

kamikazelight

総合スコア305

PowerShell

Windows PowerShellはコマンドラインインターフェースであり、システム管理を含むWindowsタスク自動化のためのスクリプト言語です。

0グッド

0クリップ

投稿2018/12/26 07:38

編集2018/12/28 01:19

前提・実現したいこと

Excelの大量のセルの複雑な書式設定を素早く行うために
XML経由で書式設定を行いたいです。

スタイルを追加してから対象のセルに追加したスタイルIDを設定すれば
出来そうなことは分かったので
元のスタイルをコピーして書き換えて追加して
もともとデフォルトのスタイルが割り当てられていたセルには"StyleID"の項目がないので
"StyleID"が無いセルはその項目を追加したいのですが
AppendChildを使えばいいらしいところまでは分かったのですが使い方がよくわかりませんでした。

上記の
配列になっている項目の追加方法と
新しいプロパティ? の追加方法と

元の項目をコピーして流用? することが可能
ならばそちらも

教えて頂きたいです。
お願い致します。

サンプルソースコード

powershell

1try 2{ 3 $App = New-Object -ComObject "Excel.Application" 4 $App.Visible = $true 5 $BK = $App.Workbooks.Add() 6 $Sh = $Bk.ActiveSheet 7 8 $App.DisplayAlerts = $false 9 $Sh.Range("A1:C4").Formula() = "=Row()*Column()" 10 $Sh.Range("A2:C2").merge() 11 $Sh.Range("A2:C2").Interior.Color = [int]"0xCCCCCC" 12 13 $XML = $Sh.Range("A1:C4").Value(11) -as "XML" 14 15 16 <# 17 ここでXMLをいじって表示形式を変更したい 18 19 そのために.... 20 $XML.Workbook.Styles に新しいスタイルを追加したい 21 22 $XML.Workbook.Worksheet.Table.Row.Cellに"StyleID"の項目が無ければ追加したい 23 #> 24 25 $XML.PreserveWhiteSpace = $true 26 $NewXmlText = $XML.OuterXml 27 Write-Host $NewXmlText 28 $Sh.Range("A1:C4").Value(11) = $NewXmlText 29 # コンソールに"Enter"入力されるまで待機 30 $null = Read-Host "Enter で終了" 31} 32catch [DivideByZeroException] 33{ 34 Write-Host "エラー" 35} 36finally 37{ 38 Write-Host "クリーンアップしています..." 39 $BK.Close($false) 40 $App.Quit() 41 42 $Null = [System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($Sh) 43 $Null = [System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($BK) 44 $Null = [System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($App) 45 [System.GC]::Collect() 46}

試したこと

AppendChildを使えばいいらしいところまでは分かったのですが
使い方がよくわかりませんでした。

補足情報(FW/ツールのバージョンなど)

Win10

蛇足( - 追記 - )

セルの結合サイズが違う場所同士でのNumberFormatや値のコピペなど
自由なコピペをしたくてそのために試行錯誤しています。

XML 以外でも下記条件を全て満たせれば XMLの要素の追加 以外の回答でもありがたいです。

-- 最終必須条件 --
既に開いているブック間のコピペ
別のプロセス間のコピペ
同じブックを複数 読取専用で開いていても 可

ペースト時に、ペースト方法選択切替
0. NumberFormat
0. セルの塗りつぶし色とパターン
0. 値(Value)の 書換 or 追記(貼り付け先の値の 先頭 or 末尾)
0. FontSize
0. FontColor

等 の組み合わせ

コピー内容を編集してからのペースト

ショートカットキー での コピペ
保存されていないブック( 一度も保存されていない, 最終保存から変更されている ) でのコピペ
異なる結合範囲間でのコピペ(結合されたセルは1つのセルとして扱う コピー範囲 よりも 貼付範囲の 方が大きければ コピー内容をループ)
複数Areaのコピペ
異なるArea.Count間 のコピペ
コピー 又は、ペースト 最中のExcel操作
上記の条件は可能な組み合わせならば複数同時に発生することあり

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

自己解決

たこはち様 の「へのかっぱ」日記をみてXMLには要素と属性という概念があることを知りました。

あとはそれぞれの操作方法を調べることで無事 理解できました。

$XMLの中身は質問文のプログラムで取得した内容とします。

powershell

1属性の作成 2$Attribute = $XML.CreateAttribute("名前") 3 4要素の作成 5$Element1 = $XML.CreateElement("名前") 6$Element2 = $XML.CreateElement("名前") 7 8属性の追加 9$Element1.Attributes.Append($Attribute) 10 11要素の追加 12Element1.AppendChild($Element2) 13 14要素のコピー 15$Element3 = $XML.Workbook.Styles.Style[1].Clone() 16 17属性のコピー 18未検証、要素と同様にClone()が存在するところまで確認 19

あとはいろいろ試しながらやっていきたいと思います。

タイトル記載の問題は解決できたので
この問題はクローズと致します。

投稿2019/01/05 01:46

kamikazelight

総合スコア305

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

時間を測定したわけではありませんが、
COM経由で弄るのであれば、XMLを編集するより、ExcelのCOM API経由で操作した方がより簡単で堅牢ではないでしょうか?

以下、今開いているブックに対してExcelのCOM API経由で新しいスタイルの作成、適用をするサンプルです。

powershell

1[scriptblock]$releaseCom = { 2 param([ref]$com) 3 if ($null -eq $com.Value -or 4 -not [System.Runtime.InteropServices.Marshal]::IsComObject($com.Value)) { 5 return 6 } 7 [System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($com.Value) > $null 8 $com.Value = $null 9} 10 11try { 12 [__ComObject]$appXl = [System.Runtime.InteropServices.Marshal]::GetActiveObject('Excel.Application') 13 [__ComObject]$wb = $appXl.ActiveWorkbook 14 15 # 適用するスタイルを作成 16 [__ComObject]$applyStyle = $wb.Styles.Add('PSTest') 17 $applyStyle.Interior.Color = 0xCCCCCC 18 # 適用する書式のチェックを外す場合は $applyStyle.Include~ を $false にする 19 20 [__ComObject]$ws = $wb.ActiveSheet 21 [__ComObject]$rng = $ws.Range('A1') 22 # 作成したスタイルを適用 23 $rng.Style = $applyStyle 24 25} finally { 26 $releaseCom.Invoke([ref]$rng) 27 $releaseCom.Invoke([ref]$ws) 28 $releaseCom.Invoke([ref]$applyStyle) 29 $releaseCom.Invoke([ref]$wb) 30 $releaseCom.Invoke([ref]$appXl) 31 [GC]::Collect() 32 [GC]::WaitForPendingFinalizers() 33 [GC]::Collect() 34}

もっとも、ExcelのCOM APIを使うならメインの処理はVBAで作成した方がより早いはずですけれど…

vba

1Private Sub SampleApplyStyle() 2 Dim appXl As Excel.Application 3 Set appXl = Excel.Application 4 5 Dim wb As Excel.Workbook 6 Set wb = appXl.ActiveWorkbook 7 8 Dim applyStyle As Excel.Style 9 Set applyStyle = wb.Styles.Add("VBAtest") 10 applyStyle.Interior.Color = &HCCCCCC 11 12 Dim ws As Excel.Worksheet 13 Set ws = wb.ActiveSheet 14 Dim rng As Excel.Range 15 Set rng = ws.Range("A2") 16 rng.Style = applyStyle 17End Sub

投稿2018/12/26 12:16

imihito

総合スコア2166

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kamikazelight

2018/12/27 01:12

回答有難うございます。 少し試してみたいと思います セルの結合サイズが違う場所同士でのNumberFormatや値のコピペを したくてそのために試行錯誤しています。 最初VBAで値のみ対応させたものを利用していたのですが 貼り付けの速度が足りず待ちの間何もできなくなってしまい困ったので 現在、非同期でVBSを呼び出して 並列で実行できるようにしています。 ですが今度は貼り付け作業が重なってくるとExcelの応答性がおちてセルの選択すらラグがひどすぎて 結局貼り付け待ちをしなければならないような状態になっています。 XMLなら取得や設定にセルを回すのに比べて時間が掛からず XMLの編集中もExcelに負荷がかからないので いけるのではないかと思ったのですが.... あとはExcelプロセスが違っているとVBAからだとわたしには厳しかったり Excel VBAからだとフォームが隠れてしまったり そのVBAを入れているブックを非表示にするとなぜかブックが入っていない空のウィンドウが出てしまい 閉じるボタンを押すと同じプロセスのブックが巻き込まれて閉じてしまうので閉じれなかったり... VBAも触るので後からコピペ用のVBAブックを開いたときにEnableEventsがFalseになっていて OpenBookイベントにショートカットキーの割り当てを入れているのですがそれが走らなかったり.... それらの問題が解決できるのであればもともとVBAでやろうとしていたのでVBAでもいいのですが いろいろ考えてもいい案が出ませんでした.... 他に手段はあるのでしょうか?
imihito

2018/12/27 09:23

# 情報のコピペの速度について 単純な書式込みのコピーをしたとき XML文字列での取得・設定と、`sourceRange.Copy(destRange)`では`Range.Copy`の方が倍近く早い結果となった事がありました。 誰でも読める形式であるXMLの変換・解釈に時間がかかるため、内部処理で完結するCOM操作の方が早いのだと思われます。 そのため、ExcelファイルそのものをOffice Open XML(OOXML)として編集するのでなければ、COM操作の方が高速だと考えています。 --- > 貼り付け作業が重なってくるとExcelの応答性がおちて~ のあたりから、手動操作用のExcelと自動処理用のExcelでインスタンスが分けられていないように感じます(インスタンスが別なら、端末負荷以外の影響は無いはず、という考えから)。 まずは、自分の手動作業用のExcelを予め立ち上げておき(ダブルクリックでファイルを開いたとき、先に起動していたインスタンスで開かれるため)、 その上で、新規のExcelのインスタンスを生成し、その中で処理用のマクロの入ったブックを開いて処理させてはどうでしょうか(マクロ自身は同じインスタンス内のものを使って処理する)。
kamikazelight

2018/12/28 00:36 編集

すみませんよくわかりませんでした。 「sourceRange.Copy(destRange)」とはRange("A1:C20").Copy 等のことでいいでしょうか? 「新規のExcelのインスタンスを生成し、その中で処理用のマクロの入ったブックを開いて処理させてはどうでしょうか(マクロ自身は同じインスタンス内のものを使って処理する)。」の「マクロの入ったブック」のマクロ と 「マクロ自身は同じインスタンス内」のマクロは別物でしょうか? 新規インスタンスでということは別のプロセスでということでいいでしょうか? あとセルの結合範囲が貼り付け元と貼り付け先で違うのと 値とNumberFormatのみコピーしたかったりするのですが 上記の方法は可能なのでしょうか? -- 追記 -- 質問文の 蛇足( - 追記 - ) に最終的に達成したい条件を載せました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問