PowerShellで中くらいのものを書くときに考えたこと その1

体調不良などがあり、少しブログを書くのを中断してしまったが、また書いていきたいと思う。

今回はPowerShellの話。

今までPowerShellVSTS上のTaskで小さいものを書いていた程度で、特に文法とかコーディングの作法とかを考えずに書いていたが、ある程度の大きさのものを作成しようと思った場合、他人が読んだ場合や自分が半年後に読んだ場合でも、すぐに理解が追い付くようなものにした方がよいと思うのでその辺をどうするか考えたものを書こうと思う。

  1. IDEや環境面
  2. コーディング規約
  3. 外部ファイル化(外部のps1ファイルの関数呼び出し)
  4. スコープ
  5. テスト

IDEや環境面

小さいものを書くのであれば、IDEなどなくとも、メモ帳でもなんでもいいという気持ちだったが、ある程度の大きなものを扱う場合、関数の一覧を見たかったり、コード補完機能が欲しくなったりして結局最終的にVS CodePowerShell拡張機能を追加して開発することにした。
今回はWindows Powershellでの開発をしたかった(Mount-DiskImageなどisoファイルを扱ったりなどがあった)ので、Windows 8.1マシンだったが、下記リンクのWMF5.1を使って、Windows PowerShellのバージョンを5.1に上げておいた。
Installing Windows PowerShell | Microsoft Docs

なお、すべてを理解したわけではないが、Windows PowerShellPowerShell Coreは違うもので、.NET Frameworkと.NET Coreみたいな関係のように見える。
Installing PowerShell | Microsoft Docs
PowerShell CoreにはMount-DiskImageなどの関数がなく、なぜ動かないんだろう・・・?ということで小一時間調べたりした。

コーディング規約

どういう規約でもある程度まともに設定されていればいいと思いますが、基本的にモジュール単位、ファイル単位で統一されたものになっていることが大事だと考えています。
調べたことはこのあたり

すごくいろいろ調べてあって、すごい。全部読みきれなかったが、自分に必要そうな部分を読み取った。
PowerShell のコーディングスタイル - tech.guitarrapc.cóm
また、命名はこのあたり。本家なので、概要から全部読み直してもいい。
PowerShell で用いられる名前の習得 | Microsoft Docs
関数のドキュメントはこのあたり。VSCodeなどのIDEから便利に使えるようにするにはドキュメントも書いておきたいのでここも読んだ。
Windows PowerShell: Build a Better Function | Microsoft Docs


読み取ったのはこのあたり

  • 変数名
    • camelCaseなのかPascalCaseなのか
      • グローバルな変数かローカルな変数かで判断した
      • グローバルな変数はPascalCaseにした
      • ローカルな変数はcamelCaseにした
      • 関数宣言の引数はPascalCaseにした
  • 関数名
    • 今回作成したモジュールでは、すべてデフォルトのスコープ設定にした
    • camelCaseとかPascalCaseではなく、Verb-Nounという形式で書く
      • Verbに設定する単語はGet-Verbsコマンドの一覧から適切なものを利用する
  • 関数ドキュメント
    • 関数の中の先頭に書く

外部ファイル化(外部のps1ファイルの関数呼び出し)

外部ファイルを読みだす場合には、下記のように書いてファイルを読み込むようなコードを追加する

. '.\hoge.ps1'

ただ、上記の記述は実行するパスからの相対参照となるので、仮に↓のような構造にしていた場合、PowerShellコンソールからmain.test.ps1を呼び出して、main.test.ps1の中でmain.ps1を呼び出し、さらにmain.ps1の中で

. '.\hoge.ps1'

とした場合には、hoge.ps1が読み込めません、という意味のエラーメッセージが出力される。
root
 ┣src-dir
 ┃ ┣hoge.ps1
 ┃ ┗main.ps1
 ┗test-dir
   ┣hoge.test.ps1
   ┗main.test.ps1

test用のファイルを上記のように作っているとこういうことになるだけで、Pesterのようなテストツールでテスト用ファイルを自動生成する際にもプロダクトコードと同じ階層に出力されるので、特に問題は発生しないのかもしれない。ただ、もし上記のようなコードでも動くようにするには、関数の中で外部ファイルを相対パスで読み込むような形にする方法があるようだ。

function New-TestFunc ($paramArgs) {
    # ps1読込
    $scriptPath = $script:MyInvocation.MyCommand.Path
    $dirPath = Split-Path -Parent $scriptPath
    $rootPath = Split-Path -Parent $dirPath
    . "$rootPath\src-dir\hoge.ps1"

    # (以下略)
}

変数のスコープとテストについては、別日に書きます。

SonarQubeとVSTSをつなげてカバレッジとか見れるようにする

仕事でSonarQubeとVSTSを連携させた話を書く。

Qiitaなどで、SonarQubeの設定記事はよくあるし、それとJenkinsやその他のCIツールとを連携させている記事は多く見かけるがVSTSと連携させている記事はあまり見かけず、少しつまった部分があったので書いておく。

SonarQubeとは何か

この説明はよくいろいろな記事があるので割愛するが、静的解析ツールの一つ。
SonarQubeを選定した理由としては、静的解析ツールはたくさん色々なものがあるが、オープンソースC#,Typescript,Javascriptなどに対応していて、参考となるドキュメントなどが多いものを調べた結果、検索でたくさんヒットしたり、記事が多かったりしたものをなんとなく選定した。
公式のドキュメントページはこの辺
Documentation - SonarQube Documentation - Doc SonarQube

VSTSとは何か

Visual Studio Team Service
タスク管理からGit、CI/CDまでさまざまなものを幅広く提供しているサービス。これだけを使っておけばASP.NETでの開発は不自由なく進められる。
VSTSを利用している理由は、開発チーム全員にMSのサブスクリプションが割り当てられていて、VSTSを利用できる体制が整っているため、C#で開発するのにVSTSをあえて使わない理由がないので、使っている。

連携設定の方法

VSTS連携設定の方法は比較的簡単で、VSTSからテストなどを実行するための Build Pipeline ( 2018年の途中までは Build Definition という名前だった)の中で、SonarQubeへの連携開始のTaskとSonarQubeへの連携終了のTaskを配置するだけ。

詳しくはここに書いてあって、最初にPrepare Analysis Configuration taskを設定して、ビルド、テストを実行し、Run Code Analysis taskを実行する。もし、Quality Gateを利用したい場合には、Publish Quality Gate Result taskも設定する。

簡単だったのだが・・・

上記までは全然つまらずにSonarQubeのドキュメント通りに進めれば問題なく進められる。
多少つまるとすれば、分析対象のプロジェクトが大きい場合、SonarQube側でOut of Memoryエラーが発生することくらい。
Out of MemoryについてはSonarQubeのドキュメントにも書いてあり環境変数を設定する。
name : SONAR_SCANNER_OPTS
value : -Xmx3072m

ここまでで、大体の作業は終わって、今回あえて記事を書こうと思ったのは、VSTS上のTest Taskが分割されていた場合には、単純に上記の設定ではコードカバレッジの連携がうまくいかないことが分かったためである。

関わっていたプロジェクトでは、順番に依存したテストをかなりの数で書いており、それらが多すぎるとVSTSのエージェント側でもOut Of Memoryとなっていたので、Test Task(C#のテストなので Visual Studio Testという名前のタスク)を分割し計4つのTest Taskを順番に実行していた。
これらをTest1, Test2, Test3, Test4という名前だとする。
VSTSのエージェント側ではTest毎にビルド用フォルダ内に、trxファイルとcoverageファイルが生成される。(Visual Studio Testタスクの中で、Code coverage enabledのチェックをONにしている場合、coverageファイルが生成される)
trxファイルとcoverageファイルはTest Task毎に似たような名前で作成されて、VSTSにアップロード後、次のTest Taskでファイルは上書きされ、差し替えられるようになっている。
そして、最後にRun Code Analysis taskによって、SonarQubeサーバにtrxファイルとcoverageファイルがアップロードされるのだが、Run Code Analysis taskが実行されるタイミングでは、最後のTest4のタスクについてのtrxファイルとcoverageファイルしか残っていないため、すべてのテストについてのテスト結果やcoverageファイルをSonarQubeに連携できないという状態だった。

テスト毎に上書きされるのだから、上書きされないようにファイルを別フォルダに退避させて、Run Code Analysis taskが実行される直前で元の場所に名前を変えるなどして戻して、trxファイル、coverageファイルを4つずつSonarqube側に連携してもらえばよいかと考えたが、どうもRun Code Analysis taskは1回のBuild Pipelineの実行において、trxファイル、coverageファイルともに、1ファイルずつしか扱えないようで、この方法は断念した。

したがって、Sonarqubeに連携するにはどうにかしてtrxファイルとcoverageファイルをマージする必要がある。

trxファイルのマージ

trxファイルのマージはいろいろとググった結果、TRX-Mergerというものがあり、これを使ってマージすることで問題なくなった。

coverageファイルのマージ

coverageファイルのマージもググったのだが、こちらはVisual Studioで用意されているexeを利用すればいいことが分かった。
変換する方法が書いてあるだけだったが、exeから複数のcoverageのファイルパスを並べて実行してしまえば問題なかった。
コマンドは下記のような形
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe" analyze /output:Summary.coveragexml 0.coverage 1.coverage 2.coverage ...


というわけで、書いた大作のpowershellが↓です。
ところどころにGet-Locationと書いてありますが、これはデバッグ用に書いたもので消してないだけなのでうまく無視していください。

前提としてフォルダ構成はこんな感じになっていると思って読んでください。
$(Build.Repository.LocalPath)\TestResults
 ┣previous
 ┃ ┣("HogeAgent-ユニーク名"形式のフォルダ)\In\("ユニーク名"のフォルダ)
 ┃ ┃ ┗.coverageファイル
 ┃ ┣("HogeAgent-ユニーク名"形式のフォルダ)\In\("ユニーク名"のフォルダ)
 ┃ ┃ ┗.coverageファイル
 ┃ ┣("HogeAgent-ユニーク名"形式のフォルダ)\In\("ユニーク名"のフォルダ)
 ┃ ┃ ┗.coverageファイル
 ┃ ┣.trxファイル
 ┃ ┣.trxファイル
 ┃ ┗.trxファイル
 ┃ (↑Test Task毎に生成されているので3つの異なるtrxファイルとcoverageファイルが退避されている)
 ┃ (↓最後のTest Taskによって作成されたtrxファイルとcoverageファイル)
 ┣("HogeAgent-ユニーク名"形式のフォルダ)\In\("ユニーク名"のフォルダ)
 ┃ ┗.coverageファイル
 ┗.trxファイル


.coverageファイルをマージして、一つのcoverage.xmlファイルに変換する
CodeCoverage.exeのパスはVisual Studio 2017用のパスを利用していますが、適宜別のバージョンに読み替えればなんとかなるかと思っています。
※この部分はVSTSPowershell Task (Version 2.*)を利用しています。

cd $(Build.Repository.LocalPath)
# collect coverage file paths
cd TestResults\previous
$targetFilePaths = @()
Get-ChildItem | ForEach-Object -Process {
  # folder name is hard code on each environment ←ここはVSTSのagentの実行者の設定などによって、テスト結果のtrxファイルやcoverageファイルが出力されるフォルダ名が変わるので、こうしています。
  if(($_.Name.StartsWith("HogeAgent") -or $_.Name.StartsWith("HogeAgent2")) -And $_.PSIsContainer){
    $InfolderName = $_.Name + "\In"
    
    cd $InfolderName
# Get-Location
    $coverageFolderName = Get-ChildItem -Name | Select-Object -First 1
    
    cd $coverageFolderName
# Get-Location
    $coverageFileName = Get-ChildItem -Name | Select-Object -First 1
#    $coverageXmlFileName = $coverageFileName + "xml"
    
Write-Output $coverageFileName
#Write-Output $coverageXmlFileName

    # convert to coveragexml
#    & "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe" analyze /output:"$coverageXmlFileName" "$coverageFileName"
    
    $targetFilePath = $InfolderName + "\" + $coverageFolderName + "\" + $coverageFileName
    $targetFilePaths = $targetFilePaths + ,$targetFilePath
    cd ..\..\..
Get-Location
  }
}

# set target merge file
# move to TestResults folder
cd ..
Get-Location
$targetCoverageFilePath = ""
Get-ChildItem | ForEach-Object -Process {
  # folder name is hard code on each environment
  if(($_.Name.StartsWith("HogeAgent") -or $_.Name.StartsWith("HogeAgent")) -And $_.PSIsContainer){
    $InfolderName = $_.Name + "\In"
    
    cd $InfolderName
    $coverageFolderName = Get-ChildItem -Name | Select-Object -First 1
    
    cd $coverageFolderName
    $coverageFileName = Get-ChildItem -Name | Select-Object -First 1

    $targetCoverageFilePath = $InfolderName + "\" + $coverageFolderName + "\" + $coverageFileName
    cd ..\..\..
  }
}

$lastCoverage = [string]$targetFilePaths.Length + ".coverage"
Copy-Item $targetCoverageFilePath -Destination $lastCoverage -Force
For ($i=0; $i -lt $targetFilePaths.Length; $i++) {
  $srcpath = "previous\" + $targetFilePaths[$i]
  $dstpath = [string]$i + ".coverage"
  Copy-Item $srcpath -Destination $dstpath -Force
}

$all_args = @("analyze", "/output:Summary.coveragexml", "0.coverage")
$coverageFiles = ,"0.coverage"
For ($i=1; $i -le $targetFilePaths.Length; $i++) {
  $cov = [string]$i + ".coverage"
  $all_args = $all_args + ,$cov
}
Write-Output $all_args

$cmd = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe"
& $cmd $all_args

Write-Output $paths


.trxファイルをマージして、一つのtrxファイルに変換する、前にtrxファイルのパスを集めたものをVSTSで利用する変数に格納する
※この部分はVSTSPowershell Task (Version 2.*)を利用しています。

cd $(Build.Repository.LocalPath)
# collect trx file paths
cd TestResults\previous
$targetFilePaths = ""
Get-ChildItem | ForEach-Object -Process {
  if($_.Name.EndsWith(".trx")){
    if($targetFilePaths -eq ""){
      $targetFilePaths = "previous\" + $_.Name
    }
    else{
      $targetFilePaths = $targetFilePaths + "," + "previous\" + $_.Name
    }
  }
}

# set target merge file
# move to TestResults folder
cd ..
Get-Location
Get-ChildItem | ForEach-Object -Process {
  if($_.Name.EndsWith(".trx")){
    $targetFilePaths = $targetFilePaths + "," + $_.Name
  }
}
Write-Output $targetFilePaths

Write-Output ("##vso[task.setvariable variable=TargetFilePaths;]$targetFilePaths")

Write-Output $targetFilePaths
cd ..

.trxファイルをマージして、一つのtrxファイルに変換する
TRX_Merger.exeはビルド後のものを利用しているので、パスがビルドされたものっぽいところになっています。
※この部分だけはVSTSPowershell Taskではなく、Command Line Taskで記述しています。理由はないですが、最初にこのTaskを書こうと思った時に、powershell から exe を叩く際の引数を複数指定する際の呼び方をよく分かっていなかったので、Command Line Taskを使っただけです。

cd $(Build.Repository.LocalPath)\TestResults

$(Build.Repository.LocalPath)\sources\Tools\trx-merger\TRX_Merger\bin\Debug\TRX_Merger.exe /trx:%TargetFilePaths% /output:Summary.trx

del HogeAgent*.trx
del HogeAgent2*.trx

上記によって、Summary.trxとSummary.codecoveragexmlが$(Build.Repository.LocalPath)\TestResultsに出力されているので、このファイルがSonarQubeに連携されるようにVSTSのBuild Pipelineでは、Prepare Analysis Configuration taskにおいて、Advanced > Additional Propertiesのところで、下記の2行を追記する。

sonar.cs.vscoveragexml.reportsPaths=**/Summary.coveragexml
sonar.cs.vstest.reportsPaths=**/Summary.trx

以上で、SonarQubeまでのコードカバレッジの連携がうまくいくようになった。

すごく長いものを書いてしまい、これは2回に分けて書くくらいでもよかったのかもしれないと感じた・・・。

XMLの名前空間

少し前に自社のASP.NETの製品に置いてWeb.configのカスタム部分をCLIで設定できるようにする作業をやっていた。

今回はその際に学んだ(正確には昔Javastrutsとか扱っていた際にも一度学んだような気もする)ものを書いておく。

まず、XDT変換する際に利用するXMLはこのようなものである。

<?xml version="1.0" encoding="utf-8"?>

<!-- web.config 変換の使用方法の詳細については、https://go.microsoft.com/fwlink/?LinkId=125889 を参照してください -->

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <appSettings>
    <!-- Remove -->
    <add key="hogeKey" xdt:Transform="Remove" xdt:Locator="Match(key)" />
  </appSettings>
</configuration>

この設定によって、configuration/appSettingsの中のhogeKeyの要素が削除されることになるというのは知っていたが
このxdtであるとかURLとかが何者であるかが分かっていないと、XDT変換用のxmlを生成するプログラムを書こうと思った際に、ドキュメントなどを読んでも、理解が難しかったので、メモをしておきたい。

下記が本当に分かりやすかったので、そのまま読んでおけばいいが、私の知っておきたかった部分だけをメモしておく
XMLにおける名前空間 - データ記述とXML

最初に用語をいくつか確認すると、

<hoge></hoge>

hoge 要素という。

<hoge>  ...  </hoge>

と要素に囲まれた中身をコンテンツという。

<hoge src="img.png" />

と書かれた場合に、これはhogeタグのsrc属性の属性値は"img.png"ということを意味する。

<!-- comment -->

と書かれたものはコメント。


さて、今回私がよく分かっていなかったのは下記の表現である。

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">

xmlnsというのは xml namespaceであり、ここではXML-Document-Transform の名前空間の名前は http://schemas.microsoft.com/XML-Document-Transform で、 これは長いので xdt という別名をつけています。

で、次がこれ。

<add key="hogeKey" xdt:Transform="Remove" xdt:Locator="Match(key)" />

この xdt:TransformというのはXDTで定められたスキーマ内のxdt:Transform属性に"Remove"を設定し、XDTで定められたスキーマ内のxdt:Locator属性"Match(key)"を設定している。

ECMA376のリファレンスを使ってxlsxファイルの中身を見る。

Excel2007から拡張子がxlsx、Office Open XML形式をサポートするようになったこと、xlsxファイルはxmlファイルをzip圧縮したものであることはみなさんご存知だと思います。

しかし、中身のxmlファイルについてはみなさんよく知らないと思いますので、この記事では、その中身について少し読めるようになりみましょう、という内容を書きたいと思います。

中身を読み解くのは簡単です。ECMA376で標準化されているため、立派なリファレンスがあります。現在は4版まで出ており、各版はPart1~Part4まで分けてファイルが存在するため、ECMA-376 4th edition Part 1~ECMA-376 4th edition Part 4を読めば、現在の仕様が分かるということになっています。非常に簡単ですね。

では、リファレンスのpdfを開いて読んでみましょう。
ECMA-376 4th edition Part 1のリンクをクリックして、zipファイルを展開して、PDFを開いて・・・。

・・・

ちょっと、5000ページというのは厳しいですね。

というわけで、方向転換して、ECMA-376のリファレンスと突き合わせながら、Excelで設定した内容とxmlファイルがどう対応しているのかを見て行くという、しょうもないことをやろうと思います。(ここまでが記事の説明)

※なお、少し時間がなく出してしまっているので、誤りがあり可能性があります。
記述内容に誤りがあった場合には訂正させていただきますので、コメントなどで指摘いただければと思います。


というわけで、ここから作業をしていきます。

まず、何も記入していないブックを用意します。

f:id:gototo:20151207143519p:plain

このブックをno-edited.xlsxというファイル名で保存し、拡張子をzipに変更して、展開します。

f:id:gototo:20151207144143p:plain

さて、ようやくxmlファイルが出てきました。
最初の[Content_Types].xmlファイルを見てみましょう。

<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
  <Default Extension="rels"
    ContentType="application/vnd.openxmlformats-package.relationships+xml" />
  <Default Extension="xml" ContentType="application/xml" />
  <Override PartName="/xl/workbook.xml"
    ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" />
  <Override PartName="/xl/worksheets/sheet1.xml"
    ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" />
  <Override PartName="/xl/theme/theme1.xml"
    ContentType="application/vnd.openxmlformats-officedocument.theme+xml" />
  <Override PartName="/xl/styles.xml"
    ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" />
  <Override PartName="/docProps/core.xml"
    ContentType="application/vnd.openxmlformats-package.core-properties+xml" />
  <Override PartName="/docProps/app.xml"
    ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" />
</Types>

xmlnsで
http://schemas.openxmlformats.org/package/2006/content-types
を指定しています。
他は。。。rels、xml、...よく分かりませんね。
しかし、なんとなく、Override PartName要素は展開されたファイルパスと合致していそうです。
あ、そうそう、展開したファイルの一覧は↓のようになっています。
/
┣[Content_Types].xml
┣_rels/
┃ ┗.rels
┣docProps/
┃ ┣app.xml
┃ ┗core.xml
┗xl/
  ┣styles.xml
  ┣workbook.xml
  ┣_rels/
  ┃ ┗workbook.xml.rels
  ┣theme/
  ┃ ┗theme1.xml
  ┗worksheets/
    ┗sheet1.xml

どれもぱっと見、よく分からないので、とりあえず、階層が浅いもの→ファイルが少ないフォルダの順に見て行きましょう。
.relsファイルはこうなっています。

<Relationships
  xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId3"
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"
    Target="docProps/app.xml" />
  <Relationship Id="rId2"
    Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"
    Target="docProps/core.xml" />
  <Relationship Id="rId1"
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
    Target="xl/workbook.xml" />
</Relationships>

app.xmlとか、core.xmlとか見たことがあるファイルがいますね。
.relsという名前からもこのファイルがzipファイル内の関連を記述しているような感じがあります。

次にapp.xmlです。

<Properties
  xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"
  xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
  <Application>Microsoft Excel</Application>
  <DocSecurity>0</DocSecurity>
  <ScaleCrop>false</ScaleCrop>
  <HeadingPairs>
    <vt:vector size="2" baseType="variant">
      <vt:variant>
        <vt:lpstr>ワークシート</vt:lpstr>
      </vt:variant>
      <vt:variant>
        <vt:i4>1</vt:i4>
      </vt:variant>
    </vt:vector>
  </HeadingPairs>
  <TitlesOfParts>
    <vt:vector size="1" baseType="lpstr">
      <vt:lpstr>Sheet1</vt:lpstr>
    </vt:vector>
  </TitlesOfParts>
  <Company />
  <LinksUpToDate>false</LinksUpToDate>
  <SharedDoc>false</SharedDoc>
  <HyperlinksChanged>false</HyperlinksChanged>
  <AppVersion>15.0300</AppVersion>
</Properties>

この辺りから、少しだけ意味の分かるものが出てきます。まず、Application要素ですが、これは何でしょうか。
Office Open XMLでは、他のofficeソフトも同様にxml形式であるため、Microsoft Excel用のファイルであるということを明示しているのでしょうか。
あと、"ワークシート"という日本語がいきなり出てきたのも気になります。
最後のAppVersionはExcel2013のバージョンで保存したことを表現しているのでしょうか。
この記事を書くのに使用したExcelはExcel2013で、バージョン情報を表示すると、15.0.4771.1000と表示されました。
この辺りで各要素の意味を知りたくなったので、PDF(Ecma Office Open XML Part 1 - Fundamentals And Markup Language Reference.pdf)内で検索してみましょう。
1203ページにある『17.16.5.14 DOCPROPERTY』辺りが定義でしょうか。
MSDN辺りでも検索してみると、下記のようなページがひっかかります。

https://msdn.microsoft.com/ja-jp/library/documentformat.openxml.extendedproperties.scalecrop(v=office.14).aspx

なるほど、ScaleCropはファイルをサムネイル表示するモードなんですかね。ってそんなのあったのか。(ググったらある・・・!)。

では、サムネイル表示されるファイルを作って

f:id:gototo:20151207170632p:plain

ファイルを展開して中身を見てみましょう。

<Properties
  xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"
  xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
  <Application>Microsoft Excel</Application>
  <DocSecurity>0</DocSecurity>
  <ScaleCrop>false</ScaleCrop>
  <HeadingPairs>
    <vt:vector size="2" baseType="variant">
      <vt:variant>
        <vt:lpstr>ワークシート</vt:lpstr>
      </vt:variant>
      <vt:variant>
        <vt:i4>1</vt:i4>
      </vt:variant>
    </vt:vector>
  </HeadingPairs>
  <TitlesOfParts>
    <vt:vector size="1" baseType="lpstr">
      <vt:lpstr>Sheet1</vt:lpstr>
    </vt:vector>
  </TitlesOfParts>
  <Company />
  <LinksUpToDate>false</LinksUpToDate>
  <SharedDoc>false</SharedDoc>
  <HyperlinksChanged>false</HyperlinksChanged>
  <AppVersion>15.0300</AppVersion>
</Properties>

あれ、変わってない!?
ああ、サムネイル表示するモードではなくて、サムネイルが表示モードによって大きいものになったり小さいものになったりするモードのON/OFF表現なんですね。
ただ、それをExcelで設定する方法が分からない。。。これについてはここまでとします。
ScaleCrop以外の要素についてもMSDNには記述されているので、もし必要になったら読むとよさそうです。
https://msdn.microsoft.com/ja-jp/library/documentformat.openxml.extendedproperties(v=office.14).aspx

さて、ScaleCropをtrueにする方法を色々ググったりしていたせいで時間も気力もなくなりつつありますが、
気を取り直して、core.xmlです。

<cp:coreProperties
  xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties"
  xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/"
  xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <dc:creator>○○ △△</dc:creator>
  <cp:lastModifiedBy>○○ △△</cp:lastModifiedBy>
  <dcterms:created xsi:type="dcterms:W3CDTF">2015-12-07T04:59:38Z</dcterms:created>
  <dcterms:modified xsi:type="dcterms:W3CDTF">2015-12-07T05:00:16Z</dcterms:modified>
</cp:coreProperties>

おや、これはファイルのプロパティの情報のようですね。
各プロパティの内容はEcma Office Open XML Part 2 - Open Packaging Conventions.pdfの41ページ付近に書いてあります。
pdfファイルを見ると、4要素だけではないですね。タイトルやバージョン番号など、様々な要素を設定することができるようです。
そういうば、確かにWindowsでファイルのプロパティ情報を見ても4要素以外にたくさん設定されています。

さて、ここまでエクセルファイルの中身について記述がされていないですね。
ということは残っているxl/フォルダ以下がエクセルファイルの中身(シートの情報など)を表現しているのでしょうきっと。
では、xlフォルダの中身を見ていきます。

まずはxl/styles.xmlです。

<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"
  mc:Ignorable="x14ac">
  <fonts count="2" x14ac:knownFonts="1">
    <font>
      <sz val="9" />
      <color theme="1" />
      <name val="Meiryo UI" />
      <family val="2" />
      <charset val="128" />
    </font>
    <font>
      <sz val="6" />
      <name val="Meiryo UI" />
      <family val="2" />
      <charset val="128" />
    </font>
  </fonts>
  <fills count="2">
    <fill>
      <patternFill patternType="none" />
    </fill>
    <fill>
      <patternFill patternType="gray125" />
    </fill>
  </fills>
  <borders count="1">
    <border>
      <left />
      <right />
      <top />
      <bottom />
      <diagonal />
    </border>
  </borders>
  <cellStyleXfs count="1">
    <xf numFmtId="0" fontId="0" fillId="0" borderId="0">
      <alignment vertical="center" />
    </xf>
  </cellStyleXfs>
  <cellXfs count="1">
    <xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0">
      <alignment vertical="center" />
    </xf>
  </cellXfs>
  <cellStyles count="1">
    <cellStyle name="標準" xfId="0" builtinId="0" />
  </cellStyles>
  <dxfs count="0" />
  <tableStyles count="0" defaultTableStyle="TableStyleMedium2"
    defaultPivotStyle="PivotStyleLight16" />
  <extLst>
    <ext xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
      uri="{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}">
      <x14:slicerStyles defaultSlicerStyle="SlicerStyleLight1" />
    </ext>
    <ext xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"
      uri="{9260A510-F301-46a8-8635-F512D64BE5F5}">
      <x15:timelineStyles defaultTimelineStyle="TimeSlicerStyleLight1" />
    </ext>
  </extLst>
</styleSheet>

styles.xmlはファイル名の通り、書式スタイルを定義しているように見えますね。
また、ここにも"標準"と日本語が設定されています。これはエクセルのリボンにあるスタイルのうち、左上にある文字列を表現しているのでしょうか?
あとは最後のext要素の中身は何を指しているのかよく分かりませんね。

PDF(Ecma Office Open XML Part 1 - Fundamentals And Markup Language Reference.pdf)内で見てみると、1744ページにある『18.8 Styles』辺りが定義のように見えます。
しかし、探すのも読むのも大変ですね。
ここはwebの力を使って、PDF検索より楽なものを探しましょう。
というわけで、↓を使います。

OOXML - Complete documentation and samples

さて、検索が楽になったので、font要素の最初のものを下記を参考に見てみましょう。

OOXML ssml:font - Complete documentation and samples

    <font>
      <sz val="9" />
      <color theme="1" />
      <name val="Meiryo UI" />
      <family val="2" />
      <charset val="128" />
    </font>

フォントサイズが9。
カラーテーマが1。
フォント名はMeiryo UI。
フォントファミリは2。
キャラクタセットは128。
ところどころよく分からないですが、これらもPDFを使ったり、ググったりすればなんとかなりそうな感がありますね。

例えば、キャラクタセットは私はぱっと見で全然分からなかったのですが、PDFを見たところ、Valueに対応した文字コードを使う事が分かります。
で、今回のものは128。つまり0x80*1shift_jisのようです。

フォントファミリはPDF(18.18.94 ST_FontFamily (Font Family)の項)を見て、
Romanを指定しているということが分かります。
なんとなく、こうやっていくと大抵のものはなんとかなりそうですね。

もう時間がないので、さっさと行きます。
次にxl/workbook.xmlです。

<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
  xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"
  mc:Ignorable="x15">
  <fileVersion appName="xl" lastEdited="6" lowestEdited="6"
    rupBuild="14420" />
  <workbookPr defaultThemeVersion="153222" />
  <mc:AlternateContent
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
    <mc:Choice Requires="x15">
      <x15ac:absPath
        xmlns:x15ac="http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac"
        url="C:\Users\USERNAME\Desktop\ecma作る\" />
    </mc:Choice>
  </mc:AlternateContent>
  <bookViews>
    <workbookView xWindow="0" yWindow="0" windowWidth="10065"
      windowHeight="3480" />
  </bookViews>
  <sheets>
    <sheet name="Sheet1" sheetId="1" r:id="rId1" />
  </sheets>
  <calcPr calcId="152511" />
  <extLst>
    <ext xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"
      uri="{140A7094-0E35-4892-8432-C4D2E57EDEB5}">
      <x15:workbookPr chartTrackingRefBase="1" />
    </ext>
  </extLst>
</workbook>

これはファイルパスやアプリケーションの情報を保存しているxmlファイルでしょうか。
xWindow="0" yWindow="0" windowWidth="10065" windowHeight="3480"
などの値はwindowサイズのように見えます。このようなものも保存してあるのですね。
詳細は省略します。

次はxl/_rels/workbook.xml.relsです。

<Relationships
  xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId3"
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"
    Target="styles.xml" />
  <Relationship Id="rId2"
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"
    Target="theme/theme1.xml" />
  <Relationship Id="rId1"
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
    Target="worksheets/sheet1.xml" />
</Relationships>

xmlファイルがそれぞれどういう役割をしているかを記述しています。


次はxl/theme/theme.xmlです。

<Relationships
  xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId3"
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"
    Target="styles.xml" />
  <Relationship Id="rId2"
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"
    Target="theme/theme1.xml" />
  <Relationship Id="rId1"
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
    Target="worksheets/sheet1.xml" />
</Relationships>

xmlファイルがそれぞれどういう役割をしているかを記述しています。

<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
  name="Office テーマ">
  <a:themeElements>
    <a:clrScheme name="Office">
      <a:dk1>
        <a:sysClr val="windowText" lastClr="000000" />
      </a:dk1>
      <a:lt1>
        <a:sysClr val="window" lastClr="FFFFFF" />
      </a:lt1>
      <a:dk2>
        <a:srgbClr val="44546A" />
      </a:dk2>
      <a:lt2>
        <a:srgbClr val="E7E6E6" />
      </a:lt2>
      <a:accent1>
        <a:srgbClr val="5B9BD5" />
      </a:accent1>
      <a:accent2>
        <a:srgbClr val="ED7D31" />
      </a:accent2>
      <a:accent3>
        <a:srgbClr val="A5A5A5" />
      </a:accent3>
      <a:accent4>
        <a:srgbClr val="FFC000" />
      </a:accent4>
      <a:accent5>
        <a:srgbClr val="4472C4" />
      </a:accent5>
      <a:accent6>
        <a:srgbClr val="70AD47" />
      </a:accent6>
      <a:hlink>
        <a:srgbClr val="0563C1" />
      </a:hlink>
      <a:folHlink>
        <a:srgbClr val="954F72" />
      </a:folHlink>
    </a:clrScheme>
    <a:fontScheme name="Office">
      <a:majorFont>
        <a:latin typeface="Calibri Light" panose="020F0302020204030204" />
        <a:ea typeface="" />
        <a:cs typeface="" />
        <a:font script="Jpan" typeface="MS Pゴシック" />
        <a:font script="Hang" typeface="?? ??" />
        <a:font script="Hans" typeface="宋体" />
        <a:font script="Hant" typeface="新細明體" />
        <a:font script="Arab" typeface="Times New Roman" />
        <a:font script="Hebr" typeface="Times New Roman" />
        <a:font script="Thai" typeface="Tahoma" />
        <a:font script="Ethi" typeface="Nyala" />
        <a:font script="Beng" typeface="Vrinda" />
        <a:font script="Gujr" typeface="Shruti" />
        <a:font script="Khmr" typeface="MoolBoran" />
        <a:font script="Knda" typeface="Tunga" />
        <a:font script="Guru" typeface="Raavi" />
        <a:font script="Cans" typeface="Euphemia" />
        <a:font script="Cher" typeface="Plantagenet Cherokee" />
        <a:font script="Yiii" typeface="Microsoft Yi Baiti" />
        <a:font script="Tibt" typeface="Microsoft Himalaya" />
        <a:font script="Thaa" typeface="MV Boli" />
        <a:font script="Deva" typeface="Mangal" />
        <a:font script="Telu" typeface="Gautami" />
        <a:font script="Taml" typeface="Latha" />
        <a:font script="Syrc" typeface="Estrangelo Edessa" />
        <a:font script="Orya" typeface="Kalinga" />
        <a:font script="Mlym" typeface="Kartika" />
        <a:font script="Laoo" typeface="DokChampa" />
        <a:font script="Sinh" typeface="Iskoola Pota" />
        <a:font script="Mong" typeface="Mongolian Baiti" />
        <a:font script="Viet" typeface="Times New Roman" />
        <a:font script="Uigh" typeface="Microsoft Uighur" />
        <a:font script="Geor" typeface="Sylfaen" />
      </a:majorFont>
      <a:minorFont>
        <a:latin typeface="Calibri" panose="020F0502020204030204" />
        <a:ea typeface="" />
        <a:cs typeface="" />
        <a:font script="Jpan" typeface="MS Pゴシック" />
        <a:font script="Hang" typeface="?? ??" />
        <a:font script="Hans" typeface="宋体" />
        <a:font script="Hant" typeface="新細明體" />
        <a:font script="Arab" typeface="Arial" />
        <a:font script="Hebr" typeface="Arial" />
        <a:font script="Thai" typeface="Tahoma" />
        <a:font script="Ethi" typeface="Nyala" />
        <a:font script="Beng" typeface="Vrinda" />
        <a:font script="Gujr" typeface="Shruti" />
        <a:font script="Khmr" typeface="DaunPenh" />
        <a:font script="Knda" typeface="Tunga" />
        <a:font script="Guru" typeface="Raavi" />
        <a:font script="Cans" typeface="Euphemia" />
        <a:font script="Cher" typeface="Plantagenet Cherokee" />
        <a:font script="Yiii" typeface="Microsoft Yi Baiti" />
        <a:font script="Tibt" typeface="Microsoft Himalaya" />
        <a:font script="Thaa" typeface="MV Boli" />
        <a:font script="Deva" typeface="Mangal" />
        <a:font script="Telu" typeface="Gautami" />
        <a:font script="Taml" typeface="Latha" />
        <a:font script="Syrc" typeface="Estrangelo Edessa" />
        <a:font script="Orya" typeface="Kalinga" />
        <a:font script="Mlym" typeface="Kartika" />
        <a:font script="Laoo" typeface="DokChampa" />
        <a:font script="Sinh" typeface="Iskoola Pota" />
        <a:font script="Mong" typeface="Mongolian Baiti" />
        <a:font script="Viet" typeface="Arial" />
        <a:font script="Uigh" typeface="Microsoft Uighur" />
        <a:font script="Geor" typeface="Sylfaen" />
      </a:minorFont>
    </a:fontScheme>
    <a:fmtScheme name="Office">
      <a:fillStyleLst>
        <a:solidFill>
          <a:schemeClr val="phClr" />
        </a:solidFill>
        <a:gradFill rotWithShape="1">
          <a:gsLst>
            <a:gs pos="0">
              <a:schemeClr val="phClr">
                <a:lumMod val="110000" />
                <a:satMod val="105000" />
                <a:tint val="67000" />
              </a:schemeClr>
            </a:gs>
            <a:gs pos="50000">
              <a:schemeClr val="phClr">
                <a:lumMod val="105000" />
                <a:satMod val="103000" />
                <a:tint val="73000" />
              </a:schemeClr>
            </a:gs>
            <a:gs pos="100000">
              <a:schemeClr val="phClr">
                <a:lumMod val="105000" />
                <a:satMod val="109000" />
                <a:tint val="81000" />
              </a:schemeClr>
            </a:gs>
          </a:gsLst>
          <a:lin ang="5400000" scaled="0" />
        </a:gradFill>
        <a:gradFill rotWithShape="1">
          <a:gsLst>
            <a:gs pos="0">
              <a:schemeClr val="phClr">
                <a:satMod val="103000" />
                <a:lumMod val="102000" />
                <a:tint val="94000" />
              </a:schemeClr>
            </a:gs>
            <a:gs pos="50000">
              <a:schemeClr val="phClr">
                <a:satMod val="110000" />
                <a:lumMod val="100000" />
                <a:shade val="100000" />
              </a:schemeClr>
            </a:gs>
            <a:gs pos="100000">
              <a:schemeClr val="phClr">
                <a:lumMod val="99000" />
                <a:satMod val="120000" />
                <a:shade val="78000" />
              </a:schemeClr>
            </a:gs>
          </a:gsLst>
          <a:lin ang="5400000" scaled="0" />
        </a:gradFill>
      </a:fillStyleLst>
      <a:lnStyleLst>
        <a:ln w="6350" cap="flat" cmpd="sng" algn="ctr">
          <a:solidFill>
            <a:schemeClr val="phClr" />
          </a:solidFill>
          <a:prstDash val="solid" />
          <a:miter lim="800000" />
        </a:ln>
        <a:ln w="12700" cap="flat" cmpd="sng" algn="ctr">
          <a:solidFill>
            <a:schemeClr val="phClr" />
          </a:solidFill>
          <a:prstDash val="solid" />
          <a:miter lim="800000" />
        </a:ln>
        <a:ln w="19050" cap="flat" cmpd="sng" algn="ctr">
          <a:solidFill>
            <a:schemeClr val="phClr" />
          </a:solidFill>
          <a:prstDash val="solid" />
          <a:miter lim="800000" />
        </a:ln>
      </a:lnStyleLst>
      <a:effectStyleLst>
        <a:effectStyle>
          <a:effectLst />
        </a:effectStyle>
        <a:effectStyle>
          <a:effectLst />
        </a:effectStyle>
        <a:effectStyle>
          <a:effectLst>
            <a:outerShdw blurRad="57150" dist="19050" dir="5400000"
              algn="ctr" rotWithShape="0">
              <a:srgbClr val="000000">
                <a:alpha val="63000" />
              </a:srgbClr>
            </a:outerShdw>
          </a:effectLst>
        </a:effectStyle>
      </a:effectStyleLst>
      <a:bgFillStyleLst>
        <a:solidFill>
          <a:schemeClr val="phClr" />
        </a:solidFill>
        <a:solidFill>
          <a:schemeClr val="phClr">
            <a:tint val="95000" />
            <a:satMod val="170000" />
          </a:schemeClr>
        </a:solidFill>
        <a:gradFill rotWithShape="1">
          <a:gsLst>
            <a:gs pos="0">
              <a:schemeClr val="phClr">
                <a:tint val="93000" />
                <a:satMod val="150000" />
                <a:shade val="98000" />
                <a:lumMod val="102000" />
              </a:schemeClr>
            </a:gs>
            <a:gs pos="50000">
              <a:schemeClr val="phClr">
                <a:tint val="98000" />
                <a:satMod val="130000" />
                <a:shade val="90000" />
                <a:lumMod val="103000" />
              </a:schemeClr>
            </a:gs>
            <a:gs pos="100000">
              <a:schemeClr val="phClr">
                <a:shade val="63000" />
                <a:satMod val="120000" />
              </a:schemeClr>
            </a:gs>
          </a:gsLst>
          <a:lin ang="5400000" scaled="0" />
        </a:gradFill>
      </a:bgFillStyleLst>
    </a:fmtScheme>
  </a:themeElements>
  <a:objectDefaults />
  <a:extraClrSchemeLst />
  <a:extLst>
    <a:ext uri="{05A4C25C-085E-4340-85A3-A5531E510DB2}">
      <thm15:themeFamily
        xmlns:thm15="http://schemas.microsoft.com/office/thememl/2012/main"
        name="Office Theme" id="{62F939B6-93AF-4DB8-9C6B-D6C7DFDC589F}" vid="{4A3C46E8-61CC-4603-A589-7422A47A8E4A}" />
    </a:ext>
  </a:extLst>
</a:theme>

ここに来て、長いファイルですね。。。
心が少し折れそうになりましたが、中身は単純に見えます。
これはExcelのテーマですね。私のExcelにはこんなにも多くのテーマが設定されていたのか。

さて、いよいよ最後のファイルです。xl/worksheets/sheet1.xmlは下記のようになっています。

<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
  xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"
  mc:Ignorable="x14ac">
  <dimension ref="A1" />
  <sheetViews>
    <sheetView tabSelected="1" workbookViewId="0" />
  </sheetViews>
  <sheetFormatPr defaultRowHeight="12" x14ac:dyDescent="0.2" />
  <sheetData />
  <phoneticPr fontId="1" />
  <pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75"
    header="0.3" footer="0.3" />
</worksheet>

おお、これはシートの情報ですね。
シート名がない?と思いましたが、xl/workbook.xmlに記述してあります。
dimension情報から、初期フォーカス一をA1にしていること、
sheetView情報からシートタブが選択状態にあるという情報が読み取れます。
他はシートのデフォルト情報ですね。
デフォルト行高さ、
デフォルト列幅、
フォント、
印刷ページのマージン

以上で、ようやく空のファイルの情報を読み取ることが出来ました。
本当はこの後に、ファイルをExcelを使用せずに作成してみれば、どういう要素がどういう関連を持って、
設定されているのかがよく分かるのですが、それは別の場所で書こうと思います。

最後に、なぜこんな重いテーマをこの12/7に書こうと思ったかという説明を少しだけ書こうと思います。
ECMA-376というのは説明なしで記述していますが、この初版は2006の12/7に出ているのです。

f:id:gototo:20151208004234p:plain
(https://en.wikipedia.org/wiki/Office_Open_XML)

というわけで、

ハッピーバースデー ECMA-376!

9歳の誕生日おめでとう!

(日付は変わってしまっていますが、まだアメリカ時間とかだと12/7の筈なのでセーフ)

業務アプリケーションはExcelと切っても切り離せない関係になってしまっているので
Office Open XMLがなくなることは今後もそうそうないでしょう。
私達に仕事をさせてくれるXMLの仕様に感謝をこめてこの記事を終わりたいと思います。

*1:10進数→16進数は(数字) to hex。16進数→10進数は(16進数) to decimalでググるのが便利です。