diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..cd7c902d
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,4 @@
+[*.cs]
+
+# SA1626: Single-line comments should not use documentation style slashes
+dotnet_diagnostic.SA1626.severity = suggestion
diff --git a/OpenXmlPowerTools.sln b/OpenXmlPowerTools.sln
index 806dc01e..f076c94a 100644
--- a/OpenXmlPowerTools.sln
+++ b/OpenXmlPowerTools.sln
@@ -1,82 +1,13 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27130.2036
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.33530.505
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenXmlPowerTools", "OpenXmlPowerTools\OpenXmlPowerTools.csproj", "{6F957FF3-AFCC-4D69-8FBC-71AE21BC45C9}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChartUpdater01", "OpenXmlPowerToolsExamples\ChartUpdater01\ChartUpdater01.csproj", "{1B03D24F-FB08-42E1-BB25-2D1BB907991B}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentBuilder01", "OpenXmlPowerToolsExamples\DocumentBuilder01\DocumentBuilder01.csproj", "{A8A6FCF0-CA4F-4637-8E66-D86603B92204}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentBuilder02", "OpenXmlPowerToolsExamples\DocumentBuilder02\DocumentBuilder02.csproj", "{BF8153AA-C390-4D00-98F2-083DEFEC7094}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentBuilder03", "OpenXmlPowerToolsExamples\DocumentBuilder03\DocumentBuilder03.csproj", "{BE635672-D3FD-42C5-96E3-EDE50E05CE29}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentBuilder04", "OpenXmlPowerToolsExamples\DocumentBuilder04\DocumentBuilder04.csproj", "{CE0ECABB-03AD-42CE-A5BD-D0CC4DCE35AB}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FieldRetriever01", "OpenXmlPowerToolsExamples\FieldRetriever01\FieldRetriever01.csproj", "{E1FD7B15-FA09-4F7F-A30E-9FBD9F765D02}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FormattingAssembler01", "OpenXmlPowerToolsExamples\FormattingAssembler01\FormattingAssembler01.csproj", "{6EAF15B6-98BE-428B-A018-A5266521551E}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Formulas01", "OpenXmlPowerToolsExamples\Formulas01\Formulas01.csproj", "{618B95DB-3A70-4DC8-BD87-00F636F72453}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlConverter01", "OpenXmlPowerToolsExamples\HtmlConverter01\HtmlConverter01.csproj", "{BC9E7408-508D-482D-8602-96E76ACBB5EA}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ListItemRetriever01", "OpenXmlPowerToolsExamples\ListItemRetriever01\ListItemRetriever01.csproj", "{04935FA6-E48B-496F-8D6A-41A59232303D}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MarkupSimplifierApp", "OpenXmlPowerToolsExamples\MarkupSimplifierApp\MarkupSimplifierApp.csproj", "{0CCE83BA-8B8B-4B98-8846-B62A61FDF170}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MetricsGetter01", "OpenXmlPowerToolsExamples\MetricsGetter01\MetricsGetter01.csproj", "{ED37372C-DFBF-4720-BD4B-CE1415961038}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenXmlRegex01", "OpenXmlPowerToolsExamples\OpenXmlRegex01\OpenXmlRegex01.csproj", "{4330D46F-6703-4BA2-844D-177F722C0820}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PivotTables01", "OpenXmlPowerToolsExamples\PivotTables01\PivotTables01.csproj", "{6785A554-BBBB-480C-8E4D-9FE90DD91A46}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PresentationBuilder01", "OpenXmlPowerToolsExamples\PresentationBuilder01\PresentationBuilder01.csproj", "{A4128935-B707-4D56-B924-27910EC92664}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PresentationBuilder02", "OpenXmlPowerToolsExamples\PresentationBuilder02\PresentationBuilder02.csproj", "{495060B4-BD80-4B18-AC44-4680F0D6D5DB}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReferenceAdder01", "OpenXmlPowerToolsExamples\ReferenceAdder01\ReferenceAdder01.csproj", "{211F05D3-F8EE-497F-9DE9-AFFA0A72140D}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevisionAccepter01", "OpenXmlPowerToolsExamples\RevisionAccepter01\RevisionAccepter01.csproj", "{84823BA5-B860-4CAF-885E-981D7F121830}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TextReplacer01", "OpenXmlPowerToolsExamples\TextReplacer01\TextReplacer01.csproj", "{5CA29B44-C4A5-4310-9429-553F0BC9FC1D}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TextReplacer02", "OpenXmlPowerToolsExamples\TextReplacer02\TextReplacer02.csproj", "{153E5218-E9C0-4ED8-9073-0802204C8B90}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentAssembler01", "OpenXmlPowerToolsExamples\DocumentAssembler01\DocumentAssembler01.csproj", "{EFE77658-EDD7-4597-8016-CBE4A18951B0}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentAssembler", "OpenXmlPowerToolsExamples\DocumentAssembler\DocumentAssembler.csproj", "{2D081A36-48F9-4A09-8247-420682545492}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpreadsheetWriter01", "OpenXmlPowerToolsExamples\SpreadsheetWriter01\SpreadsheetWriter01.csproj", "{0911F996-DF86-4FB1-A1CE-0539599EC0E0}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpreadsheetWriter02", "OpenXmlPowerToolsExamples\SpreadsheetWriter02\SpreadsheetWriter02.csproj", "{DF1D84AF-27B8-4F87-A673-CCFADC3AAF02}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenXmlPowerTools.Tests", "OpenXmlPowerTools.Tests\OpenXmlPowerTools.Tests.csproj", "{B1328B70-33B8-40E0-A729-38C34D659B5C}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentAssembler02", "OpenXmlPowerToolsExamples\DocumentAssembler02\DocumentAssembler02.csproj", "{D6DFAC7C-82F4-4318-A9F0-6450D2945D96}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlToWmlConverter01", "OpenXmlPowerToolsExamples\HtmlToWmlConverter01\HtmlToWmlConverter01.csproj", "{9E194D13-F5A0-4430-8F87-D74326457385}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocumentAssembler03", "OpenXmlPowerToolsExamples\DocumentAssembler03\DocumentAssembler03.csproj", "{214F0E80-D2E3-4E19-A3FC-2BE15B3906B0}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlToWmlConverter02", "OpenXmlPowerToolsExamples\HtmlToWmlConverter02\HtmlToWmlConverter02.csproj", "{1E75CB7D-2A4A-4B03-80A9-7B7D59B18BB4}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WmlToHtmlConverter01", "OpenXmlPowerToolsExamples\WmlToHtmlConverter01\WmlToHtmlConverter01.csproj", "{396D9209-0D9A-4E61-9471-04C71F6CA6B9}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WmlToHtmlConverter02", "OpenXmlPowerToolsExamples\WmlToHtmlConverter02\WmlToHtmlConverter02.csproj", "{D4078011-2611-46A7-8A30-55E4AB8FA786}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SmlDataRetriever01", "OpenXmlPowerToolsExamples\SmlDataRetriever01\SmlDataRetriever01.csproj", "{DCE8EC51-1E58-49A0-82CF-5BE269FA0A9D}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WmlComparer01", "OpenXmlPowerToolsExamples\WmlComparer01\WmlComparer01.csproj", "{C9CAA69C-575A-442E-9D8A-69C53B39D72C}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WmlComparer02", "OpenXmlPowerToolsExamples\WmlComparer02\WmlComparer02.csproj", "{3D1C46E1-7A9E-4A4B-8D95-68613603DEDF}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{A83D6B58-6D38-46AF-8C20-5CFC170A1063}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9AFB8C96-1E6E-483E-9882-75D2483E7076}"
ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
LICENSE.txt = LICENSE.txt
@@ -95,181 +26,10 @@ Global
{6F957FF3-AFCC-4D69-8FBC-71AE21BC45C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6F957FF3-AFCC-4D69-8FBC-71AE21BC45C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6F957FF3-AFCC-4D69-8FBC-71AE21BC45C9}.Release|Any CPU.Build.0 = Release|Any CPU
- {1B03D24F-FB08-42E1-BB25-2D1BB907991B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1B03D24F-FB08-42E1-BB25-2D1BB907991B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1B03D24F-FB08-42E1-BB25-2D1BB907991B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1B03D24F-FB08-42E1-BB25-2D1BB907991B}.Release|Any CPU.Build.0 = Release|Any CPU
- {A8A6FCF0-CA4F-4637-8E66-D86603B92204}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A8A6FCF0-CA4F-4637-8E66-D86603B92204}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A8A6FCF0-CA4F-4637-8E66-D86603B92204}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A8A6FCF0-CA4F-4637-8E66-D86603B92204}.Release|Any CPU.Build.0 = Release|Any CPU
- {BF8153AA-C390-4D00-98F2-083DEFEC7094}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {BF8153AA-C390-4D00-98F2-083DEFEC7094}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {BF8153AA-C390-4D00-98F2-083DEFEC7094}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {BF8153AA-C390-4D00-98F2-083DEFEC7094}.Release|Any CPU.Build.0 = Release|Any CPU
- {BE635672-D3FD-42C5-96E3-EDE50E05CE29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {BE635672-D3FD-42C5-96E3-EDE50E05CE29}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {BE635672-D3FD-42C5-96E3-EDE50E05CE29}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {BE635672-D3FD-42C5-96E3-EDE50E05CE29}.Release|Any CPU.Build.0 = Release|Any CPU
- {CE0ECABB-03AD-42CE-A5BD-D0CC4DCE35AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {CE0ECABB-03AD-42CE-A5BD-D0CC4DCE35AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {CE0ECABB-03AD-42CE-A5BD-D0CC4DCE35AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {CE0ECABB-03AD-42CE-A5BD-D0CC4DCE35AB}.Release|Any CPU.Build.0 = Release|Any CPU
- {E1FD7B15-FA09-4F7F-A30E-9FBD9F765D02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {E1FD7B15-FA09-4F7F-A30E-9FBD9F765D02}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {E1FD7B15-FA09-4F7F-A30E-9FBD9F765D02}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {E1FD7B15-FA09-4F7F-A30E-9FBD9F765D02}.Release|Any CPU.Build.0 = Release|Any CPU
- {6EAF15B6-98BE-428B-A018-A5266521551E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {6EAF15B6-98BE-428B-A018-A5266521551E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6EAF15B6-98BE-428B-A018-A5266521551E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {6EAF15B6-98BE-428B-A018-A5266521551E}.Release|Any CPU.Build.0 = Release|Any CPU
- {618B95DB-3A70-4DC8-BD87-00F636F72453}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {618B95DB-3A70-4DC8-BD87-00F636F72453}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {618B95DB-3A70-4DC8-BD87-00F636F72453}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {618B95DB-3A70-4DC8-BD87-00F636F72453}.Release|Any CPU.Build.0 = Release|Any CPU
- {BC9E7408-508D-482D-8602-96E76ACBB5EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {BC9E7408-508D-482D-8602-96E76ACBB5EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {BC9E7408-508D-482D-8602-96E76ACBB5EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {BC9E7408-508D-482D-8602-96E76ACBB5EA}.Release|Any CPU.Build.0 = Release|Any CPU
- {04935FA6-E48B-496F-8D6A-41A59232303D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {04935FA6-E48B-496F-8D6A-41A59232303D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {04935FA6-E48B-496F-8D6A-41A59232303D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {04935FA6-E48B-496F-8D6A-41A59232303D}.Release|Any CPU.Build.0 = Release|Any CPU
- {0CCE83BA-8B8B-4B98-8846-B62A61FDF170}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0CCE83BA-8B8B-4B98-8846-B62A61FDF170}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0CCE83BA-8B8B-4B98-8846-B62A61FDF170}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0CCE83BA-8B8B-4B98-8846-B62A61FDF170}.Release|Any CPU.Build.0 = Release|Any CPU
- {ED37372C-DFBF-4720-BD4B-CE1415961038}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {ED37372C-DFBF-4720-BD4B-CE1415961038}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {ED37372C-DFBF-4720-BD4B-CE1415961038}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {ED37372C-DFBF-4720-BD4B-CE1415961038}.Release|Any CPU.Build.0 = Release|Any CPU
- {4330D46F-6703-4BA2-844D-177F722C0820}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {4330D46F-6703-4BA2-844D-177F722C0820}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {4330D46F-6703-4BA2-844D-177F722C0820}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {4330D46F-6703-4BA2-844D-177F722C0820}.Release|Any CPU.Build.0 = Release|Any CPU
- {6785A554-BBBB-480C-8E4D-9FE90DD91A46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {6785A554-BBBB-480C-8E4D-9FE90DD91A46}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6785A554-BBBB-480C-8E4D-9FE90DD91A46}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {6785A554-BBBB-480C-8E4D-9FE90DD91A46}.Release|Any CPU.Build.0 = Release|Any CPU
- {A4128935-B707-4D56-B924-27910EC92664}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A4128935-B707-4D56-B924-27910EC92664}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A4128935-B707-4D56-B924-27910EC92664}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A4128935-B707-4D56-B924-27910EC92664}.Release|Any CPU.Build.0 = Release|Any CPU
- {495060B4-BD80-4B18-AC44-4680F0D6D5DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {495060B4-BD80-4B18-AC44-4680F0D6D5DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {495060B4-BD80-4B18-AC44-4680F0D6D5DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {495060B4-BD80-4B18-AC44-4680F0D6D5DB}.Release|Any CPU.Build.0 = Release|Any CPU
- {211F05D3-F8EE-497F-9DE9-AFFA0A72140D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {211F05D3-F8EE-497F-9DE9-AFFA0A72140D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {211F05D3-F8EE-497F-9DE9-AFFA0A72140D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {211F05D3-F8EE-497F-9DE9-AFFA0A72140D}.Release|Any CPU.Build.0 = Release|Any CPU
- {84823BA5-B860-4CAF-885E-981D7F121830}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {84823BA5-B860-4CAF-885E-981D7F121830}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {84823BA5-B860-4CAF-885E-981D7F121830}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {84823BA5-B860-4CAF-885E-981D7F121830}.Release|Any CPU.Build.0 = Release|Any CPU
- {5CA29B44-C4A5-4310-9429-553F0BC9FC1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5CA29B44-C4A5-4310-9429-553F0BC9FC1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5CA29B44-C4A5-4310-9429-553F0BC9FC1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5CA29B44-C4A5-4310-9429-553F0BC9FC1D}.Release|Any CPU.Build.0 = Release|Any CPU
- {153E5218-E9C0-4ED8-9073-0802204C8B90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {153E5218-E9C0-4ED8-9073-0802204C8B90}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {153E5218-E9C0-4ED8-9073-0802204C8B90}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {153E5218-E9C0-4ED8-9073-0802204C8B90}.Release|Any CPU.Build.0 = Release|Any CPU
- {EFE77658-EDD7-4597-8016-CBE4A18951B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {EFE77658-EDD7-4597-8016-CBE4A18951B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {EFE77658-EDD7-4597-8016-CBE4A18951B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {EFE77658-EDD7-4597-8016-CBE4A18951B0}.Release|Any CPU.Build.0 = Release|Any CPU
- {2D081A36-48F9-4A09-8247-420682545492}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2D081A36-48F9-4A09-8247-420682545492}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2D081A36-48F9-4A09-8247-420682545492}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2D081A36-48F9-4A09-8247-420682545492}.Release|Any CPU.Build.0 = Release|Any CPU
- {0911F996-DF86-4FB1-A1CE-0539599EC0E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0911F996-DF86-4FB1-A1CE-0539599EC0E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0911F996-DF86-4FB1-A1CE-0539599EC0E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0911F996-DF86-4FB1-A1CE-0539599EC0E0}.Release|Any CPU.Build.0 = Release|Any CPU
- {DF1D84AF-27B8-4F87-A673-CCFADC3AAF02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {DF1D84AF-27B8-4F87-A673-CCFADC3AAF02}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {DF1D84AF-27B8-4F87-A673-CCFADC3AAF02}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {DF1D84AF-27B8-4F87-A673-CCFADC3AAF02}.Release|Any CPU.Build.0 = Release|Any CPU
- {B1328B70-33B8-40E0-A729-38C34D659B5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B1328B70-33B8-40E0-A729-38C34D659B5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B1328B70-33B8-40E0-A729-38C34D659B5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B1328B70-33B8-40E0-A729-38C34D659B5C}.Release|Any CPU.Build.0 = Release|Any CPU
- {D6DFAC7C-82F4-4318-A9F0-6450D2945D96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D6DFAC7C-82F4-4318-A9F0-6450D2945D96}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D6DFAC7C-82F4-4318-A9F0-6450D2945D96}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D6DFAC7C-82F4-4318-A9F0-6450D2945D96}.Release|Any CPU.Build.0 = Release|Any CPU
- {9E194D13-F5A0-4430-8F87-D74326457385}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {9E194D13-F5A0-4430-8F87-D74326457385}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {9E194D13-F5A0-4430-8F87-D74326457385}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {9E194D13-F5A0-4430-8F87-D74326457385}.Release|Any CPU.Build.0 = Release|Any CPU
- {214F0E80-D2E3-4E19-A3FC-2BE15B3906B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {214F0E80-D2E3-4E19-A3FC-2BE15B3906B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {214F0E80-D2E3-4E19-A3FC-2BE15B3906B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {214F0E80-D2E3-4E19-A3FC-2BE15B3906B0}.Release|Any CPU.Build.0 = Release|Any CPU
- {1E75CB7D-2A4A-4B03-80A9-7B7D59B18BB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1E75CB7D-2A4A-4B03-80A9-7B7D59B18BB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1E75CB7D-2A4A-4B03-80A9-7B7D59B18BB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1E75CB7D-2A4A-4B03-80A9-7B7D59B18BB4}.Release|Any CPU.Build.0 = Release|Any CPU
- {396D9209-0D9A-4E61-9471-04C71F6CA6B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {396D9209-0D9A-4E61-9471-04C71F6CA6B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {396D9209-0D9A-4E61-9471-04C71F6CA6B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {396D9209-0D9A-4E61-9471-04C71F6CA6B9}.Release|Any CPU.Build.0 = Release|Any CPU
- {D4078011-2611-46A7-8A30-55E4AB8FA786}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D4078011-2611-46A7-8A30-55E4AB8FA786}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D4078011-2611-46A7-8A30-55E4AB8FA786}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D4078011-2611-46A7-8A30-55E4AB8FA786}.Release|Any CPU.Build.0 = Release|Any CPU
- {DCE8EC51-1E58-49A0-82CF-5BE269FA0A9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {DCE8EC51-1E58-49A0-82CF-5BE269FA0A9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {DCE8EC51-1E58-49A0-82CF-5BE269FA0A9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {DCE8EC51-1E58-49A0-82CF-5BE269FA0A9D}.Release|Any CPU.Build.0 = Release|Any CPU
- {C9CAA69C-575A-442E-9D8A-69C53B39D72C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C9CAA69C-575A-442E-9D8A-69C53B39D72C}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C9CAA69C-575A-442E-9D8A-69C53B39D72C}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C9CAA69C-575A-442E-9D8A-69C53B39D72C}.Release|Any CPU.Build.0 = Release|Any CPU
- {3D1C46E1-7A9E-4A4B-8D95-68613603DEDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {3D1C46E1-7A9E-4A4B-8D95-68613603DEDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {3D1C46E1-7A9E-4A4B-8D95-68613603DEDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {3D1C46E1-7A9E-4A4B-8D95-68613603DEDF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {1B03D24F-FB08-42E1-BB25-2D1BB907991B} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {A8A6FCF0-CA4F-4637-8E66-D86603B92204} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {BF8153AA-C390-4D00-98F2-083DEFEC7094} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {BE635672-D3FD-42C5-96E3-EDE50E05CE29} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {CE0ECABB-03AD-42CE-A5BD-D0CC4DCE35AB} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {E1FD7B15-FA09-4F7F-A30E-9FBD9F765D02} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {6EAF15B6-98BE-428B-A018-A5266521551E} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {618B95DB-3A70-4DC8-BD87-00F636F72453} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {BC9E7408-508D-482D-8602-96E76ACBB5EA} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {04935FA6-E48B-496F-8D6A-41A59232303D} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {0CCE83BA-8B8B-4B98-8846-B62A61FDF170} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {ED37372C-DFBF-4720-BD4B-CE1415961038} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {4330D46F-6703-4BA2-844D-177F722C0820} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {6785A554-BBBB-480C-8E4D-9FE90DD91A46} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {A4128935-B707-4D56-B924-27910EC92664} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {495060B4-BD80-4B18-AC44-4680F0D6D5DB} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {211F05D3-F8EE-497F-9DE9-AFFA0A72140D} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {84823BA5-B860-4CAF-885E-981D7F121830} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {5CA29B44-C4A5-4310-9429-553F0BC9FC1D} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {153E5218-E9C0-4ED8-9073-0802204C8B90} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {EFE77658-EDD7-4597-8016-CBE4A18951B0} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {2D081A36-48F9-4A09-8247-420682545492} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {0911F996-DF86-4FB1-A1CE-0539599EC0E0} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {DF1D84AF-27B8-4F87-A673-CCFADC3AAF02} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {D6DFAC7C-82F4-4318-A9F0-6450D2945D96} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {9E194D13-F5A0-4430-8F87-D74326457385} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {214F0E80-D2E3-4E19-A3FC-2BE15B3906B0} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {1E75CB7D-2A4A-4B03-80A9-7B7D59B18BB4} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {396D9209-0D9A-4E61-9471-04C71F6CA6B9} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {D4078011-2611-46A7-8A30-55E4AB8FA786} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {DCE8EC51-1E58-49A0-82CF-5BE269FA0A9D} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {C9CAA69C-575A-442E-9D8A-69C53B39D72C} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- {3D1C46E1-7A9E-4A4B-8D95-68613603DEDF} = {A83D6B58-6D38-46AF-8C20-5CFC170A1063}
- EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E623EFF5-2CA4-4FA0-B3AB-53F921DA212E}
EndGlobalSection
diff --git a/OpenXmlPowerTools/ChartUpdater.cs b/OpenXmlPowerTools/ChartUpdater.cs
index 79b0f74b..908c3fab 100644
--- a/OpenXmlPowerTools/ChartUpdater.cs
+++ b/OpenXmlPowerTools/ChartUpdater.cs
@@ -58,6 +58,12 @@ public class ChartData
public string[] CategoryNames;
public double[][] Values;
+
+ ///
+ /// 组合图表中,次轴图表的序列名称映射
+ /// 映射规则为:chatData中的序列名对应模板中的序列名。
+ ///
+ public Dictionary SecondChartSeriesNames { get; set; } = new Dictionary();
}
public class ChartUpdater
@@ -94,7 +100,14 @@ public static void UpdateChart(ChartPart chartPart, ChartData chartData)
throw new ArgumentException("Invalid chart data");
}
+ UpdateEmbeddedWorkbook(chartPart, chartData);
+
UpdateSeries(chartPart, chartData);
+ //如果设置了次轴,更新次轴
+ if (chartData.SecondChartSeriesNames.Count > 0)
+ {
+ UpdateSeries(chartPart, chartData, true);
+ }
}
private static Dictionary FormatCodes = new Dictionary()
@@ -129,13 +142,44 @@ public static void UpdateChart(ChartPart chartPart, ChartData chartData)
{ 49, "@" },
};
- private static void UpdateSeries(ChartPart chartPart, ChartData chartData)
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// 设置次级坐标,默认为false
+ ///
+ private static void UpdateSeries(ChartPart chartPart, ChartData chartData, bool setSecond = false)
{
- UpdateEmbeddedWorkbook(chartPart, chartData);
-
+ // update series
XDocument cpXDoc = chartPart.GetXDocument();
XElement root = cpXDoc.Root;
- var firstSeries = root.Descendants(C.ser).FirstOrDefault();
+
+ // 序列名
+ var seriesNames = chartData.SeriesNames.Except(chartData.SecondChartSeriesNames.Keys);
+ if (setSecond)
+ {
+ seriesNames = chartData.SecondChartSeriesNames.Keys;
+ }
+
+ var series = root.Descendants(C.ser).ToList();
+ // 如果不处理次轴
+ if (!setSecond)
+ {
+ series = series.Where(x => x.Descendants(C.tx).SelectMany(tx => tx.Descendants(C.v)).Any(v => !chartData.SecondChartSeriesNames.Values.Contains(v.Value))).ToList();
+
+ if (series == null || series.Count == 0)
+ throw new OpenXmlPowerToolsException("未找到图表主序列");
+ }
+ else // 处理次轴
+ {
+ series = series.Where(x => x.Descendants(C.tx).SelectMany(tx => tx.Descendants(C.v)).Any(v => chartData.SecondChartSeriesNames.Values.Contains(v.Value))).ToList();
+
+ if (series == null || series.Count == 0)
+ throw new OpenXmlPowerToolsException("未找到次轴序列,请检查次轴映射字典");
+ }
+
+ var firstSeries = series.FirstOrDefault();
var numRef = firstSeries.Elements(C.val).Elements(C.numRef).FirstOrDefault();
string sheetName = null;
var f = (string)firstSeries.Descendants(C.f).FirstOrDefault();
@@ -151,6 +195,9 @@ private static void UpdateSeries(ChartPart chartPart, ChartData chartData)
{
XElement cat = null;
+ if (!seriesNames.Contains(sn))
+ return null;
+
var oldCat = firstSeries.Elements(C.cat).FirstOrDefault();
if (oldCat == null)
throw new OpenXmlPowerToolsException("Invalid chart markup");
@@ -379,6 +426,10 @@ private static void UpdateSeries(ChartPart chartPart, ChartData chartData)
newSer = (XElement)UpdateAccentTransform(newSer, accentNumber);
return newSer;
});
+
+ // 删除newSetOfSeries中null的项目
+ newSetOfSeries = newSetOfSeries.Where(x => x != null).ToList();
+
firstSeries.ReplaceWith(newSetOfSeries);
chartPart.PutXDocument();
}
@@ -427,7 +478,7 @@ private static void UpdateEmbeddedWorkbook(ChartPart chartPart, ChartData chartD
var firstRow = new XElement(S.row,
new XAttribute("r", "1"),
new XAttribute("spans", string.Format("1:{0}", chartData.SeriesNames.Length + 1)),
- new [] { new XElement(S.c,
+ new[] { new XElement(S.c,
new XAttribute("r", "A1"),
new XAttribute("t", "str"),
new XElement(S.v,
diff --git a/OpenXmlPowerTools/DocumentAssembler.cs b/OpenXmlPowerTools/DocumentAssembler.cs
index f4d9673e..1a1f724d 100644
--- a/OpenXmlPowerTools/DocumentAssembler.cs
+++ b/OpenXmlPowerTools/DocumentAssembler.cs
@@ -483,6 +483,7 @@ private static string ValidatePerSchema(XElement element)
+
",
@@ -575,6 +576,8 @@ private class PA
public static XName Match = "Match";
public static XName NotMatch = "NotMatch";
public static XName Depth = "Depth";
+
+ public static XName HeaderRowCount = "HeaderRowCount";
}
private class PASchemaSet
@@ -600,8 +603,8 @@ static object ContentReplacementTransform(XNode node, XElement data, TemplateErr
XElement para = element.Descendants(W.p).FirstOrDefault();
XElement run = element.Descendants(W.r).FirstOrDefault();
- var xPath = (string) element.Attribute(PA.Select);
- var optionalString = (string) element.Attribute(PA.Optional);
+ var xPath = (string)element.Attribute(PA.Select);
+ var optionalString = (string)element.Attribute(PA.Optional);
bool optional = (optionalString != null && optionalString.ToLower() == "true");
string newValue;
@@ -618,7 +621,7 @@ static object ContentReplacementTransform(XNode node, XElement data, TemplateErr
{
XElement p = new XElement(W.p, para.Elements(W.pPr));
- foreach(string line in newValue.Split('\n'))
+ foreach (string line in newValue.Split('\n'))
{
p.Add(new XElement(W.r,
para.Elements(W.r).Elements(W.rPr).FirstOrDefault(),
@@ -630,7 +633,7 @@ static object ContentReplacementTransform(XNode node, XElement data, TemplateErr
else
{
List list = new List();
- foreach(string line in newValue.Split('\n'))
+ foreach (string line in newValue.Split('\n'))
{
list.Add(new XElement(W.r,
run.Elements().Where(e => e.Name != W.t),
@@ -692,11 +695,21 @@ static object ContentReplacementTransform(XNode node, XElement data, TemplateErr
}
if (tableData.Count() == 0)
return CreateContextErrorMessage(element, "Table Select returned no data", templateError);
+
+
+
+ int? headerRowCountAttr = (int?)element.Attribute(PA.HeaderRowCount) ?? 1;
+ if (headerRowCountAttr.Value < 1)
+ {
+ headerRowCountAttr = 1;
+ }
+ var headerRowCount = headerRowCountAttr.Value;
+
XElement table = element.Element(W.tbl);
- XElement protoRow = table.Elements(W.tr).Skip(1).FirstOrDefault();
+ XElement protoRow = table.Elements(W.tr).Skip(headerRowCount).FirstOrDefault();
var footerRowsBeforeTransform = table
.Elements(W.tr)
- .Skip(2)
+ .Skip(headerRowCount + 1)
.ToList();
var footerRows = footerRowsBeforeTransform
.Select(x => ContentReplacementTransform(x, data, templateError))
@@ -707,7 +720,7 @@ static object ContentReplacementTransform(XNode node, XElement data, TemplateErr
protoRow.Descendants(W.bookmarkEnd).Remove();
XElement newTable = new XElement(W.tbl,
table.Elements().Where(e => e.Name != W.tr),
- table.Elements(W.tr).FirstOrDefault(),
+ table.Elements(W.tr).Take(headerRowCount),
tableData.Select(d =>
new XElement(W.tr,
protoRow.Elements().Where(r => r.Name != W.tc),
@@ -756,17 +769,17 @@ static object ContentReplacementTransform(XNode node, XElement data, TemplateErr
if (match != null && notMatch != null)
return CreateContextErrorMessage(element, "Conditional: Cannot specify both Match and NotMatch", templateError);
- string testValue = null;
-
+ string testValue = null;
+
try
{
testValue = EvaluateXPathToString(data, xPath, false);
}
- catch (XPathException e)
+ catch (XPathException e)
{
return CreateContextErrorMessage(element, e.Message, templateError);
}
-
+
if ((match != null && testValue == match) || (notMatch != null && testValue != notMatch))
{
var content = element.Elements().Select(e => ContentReplacementTransform(e, data, templateError));
@@ -815,14 +828,14 @@ private static XElement CreateParaErrorMessage(string errorMessage, TemplateErro
return errorPara;
}
- private static string EvaluateXPathToString(XElement element, string xPath, bool optional )
+ private static string EvaluateXPathToString(XElement element, string xPath, bool optional)
{
object xPathSelectResult;
try
{
//support some cells in the table may not have an xpath expression.
if (String.IsNullOrWhiteSpace(xPath)) return String.Empty;
-
+
xPathSelectResult = element.XPathEvaluate(xPath);
}
catch (XPathException e)
@@ -832,7 +845,7 @@ private static string EvaluateXPathToString(XElement element, string xPath, bool
if ((xPathSelectResult is IEnumerable) && !(xPathSelectResult is string))
{
- var selectedData = ((IEnumerable) xPathSelectResult).Cast();
+ var selectedData = ((IEnumerable)xPathSelectResult).Cast();
if (!selectedData.Any())
{
if (optional) return string.Empty;
@@ -843,11 +856,11 @@ private static string EvaluateXPathToString(XElement element, string xPath, bool
throw new XPathException(string.Format("XPath expression ({0}) returned more than one node", xPath));
}
- XObject selectedDatum = selectedData.First();
-
- if (selectedDatum is XElement) return ((XElement) selectedDatum).Value;
+ XObject selectedDatum = selectedData.First();
+
+ if (selectedDatum is XElement) return ((XElement)selectedDatum).Value;
- if (selectedDatum is XAttribute) return ((XAttribute) selectedDatum).Value;
+ if (selectedDatum is XAttribute) return ((XAttribute)selectedDatum).Value;
}
return xPathSelectResult.ToString();
diff --git a/OpenXmlPowerTools/GlobalSuppressions.cs b/OpenXmlPowerTools/GlobalSuppressions.cs
new file mode 100644
index 00000000..64410479
--- /dev/null
+++ b/OpenXmlPowerTools/GlobalSuppressions.cs
@@ -0,0 +1,20 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// Project-level suppressions either have no target or are given
+// a specific target and scoped to a namespace, type, member, etc.
+
+using System.Diagnostics.CodeAnalysis;
+[assembly: SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1004:Documentation lines should begin with single space", Justification = "<挂起>")]
+[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1612:Element parameter documentation should match element parameters", Justification = "<挂起>")]
+[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1616:Element return value documentation should have text", Justification = "<挂起>")]
+[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1617:Void return value should not be documented", Justification = "<挂起>")]
+[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1614:Element parameter documentation should have text", Justification = "<挂起>")]
+[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1627:Documentation text should not be empty", Justification = "<挂起>")]
+[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1606:Element documentation should have summary text", Justification = "<挂起>")]
+[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1629:Documentation text should end with a period", Justification = "<挂起>")]
+[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1623:Property summary documentation should match accessors", Justification = "<挂起>")]
+[assembly: SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1514:Element documentation header should be preceded by blank line", Justification = "<挂起>")]
+[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1626:Single-line comments should not use documentation style slashes", Justification = "<挂起>")]
+[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1636:File header copyright text should match", Justification = "<挂起>")]
+[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1642:Constructor summary documentation should begin with standard text", Justification = "<挂起>")]
+[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:File should have header", Justification = "<挂起>")]
diff --git a/OpenXmlPowerTools/Helpers/ImageHelper.cs b/OpenXmlPowerTools/Helpers/ImageHelper.cs
new file mode 100644
index 00000000..822f28d9
--- /dev/null
+++ b/OpenXmlPowerTools/Helpers/ImageHelper.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace OpenXmlPowerTools.Helpers
+{
+ public class ImageHelper
+ {
+ public static (int width, int height) GetImageMetrics(Stream imageData, ImageFormat imageFormat)
+ {
+ var width = 0;
+ var height = 0;
+
+ if (imageFormat == ImageFormat.Emf)
+ {
+ using (var metafile = new Metafile(imageData))
+ {
+ width = metafile.Width; // 获取宽度
+ height = metafile.Height; // 获取高度
+ }
+ }
+ else
+ {
+ using (var image = Image.FromStream(imageData))
+ {
+ width = image.Width; // 获取宽度
+ height = image.Height; // 获取高度
+ }
+ }
+
+ return (width, height);
+ }
+
+ ///
+ /// 获取图片的宽和高
+ ///
+ ///
+ ///
+ public static (int width, int height) GetImageMetrics(string newImagePath, ImageFormat imageFormat)
+ {
+ var ext = Path.GetExtension(newImagePath).ToLower();
+ var stream = File.OpenRead(newImagePath);
+ return GetImageMetrics(stream, imageFormat);
+ }
+ }
+}
diff --git a/OpenXmlPowerTools/ImageReplacer.cs b/OpenXmlPowerTools/ImageReplacer.cs
new file mode 100644
index 00000000..579fea53
--- /dev/null
+++ b/OpenXmlPowerTools/ImageReplacer.cs
@@ -0,0 +1,245 @@
+using DocumentFormat.OpenXml.Packaging;
+using DocumentFormat.OpenXml.Wordprocessing;
+using OpenXmlPowerTools.Helpers;
+using System;
+using System.Collections.Generic;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Xml.Linq;
+
+namespace OpenXmlPowerTools
+{
+ ///
+ /// 图片替换器
+ ///
+ public class ImageUpdater
+ {
+ private readonly ImageFormat _imageFormat;
+
+ ///
+ /// 设置的宽度,可以为百分比,如果不填则默认使用页面宽度
+ ///
+ private readonly string _width;
+
+ ///
+ /// 设置高度,可以为百分比,如果不填则根据宽度缩放后自适应
+ ///
+ private readonly string _height;
+
+ public byte[] ImageBytes { get; private set; }
+
+ ///
+ /// 图片替换器构造函数
+ ///
+ /// 新图片的字节数组
+ public ImageUpdater(byte[] imageBytes, ImageFormat imageFormat, string width = null, string height = null)
+ {
+ ImageBytes = imageBytes;
+ _imageFormat = imageFormat;
+ _width = width;
+ _height = height;
+ }
+
+ ///
+ /// 新图片路径
+ ///
+ ///
+ public ImageUpdater(string newImagePath, ImageFormat imageFormat, string width = null, string height = null)
+ {
+ ImageBytes = File.ReadAllBytes(newImagePath);
+ _imageFormat = imageFormat;
+ _width = width;
+ _height = height;
+ }
+
+ ///
+ /// 替换图片
+ ///
+ /// Word文档对象
+ /// 要替换的控件tag
+ /// 新图片的路径
+ ///
+ public static bool ReplaceImage(WordprocessingDocument wDoc,
+ string contentControlTag,
+ string newImagePath,
+ ImageFormat imageFormat,
+ string width = null,
+ string height = null)
+ {
+ var replacer = new ImageUpdater(newImagePath, imageFormat, width, height);
+ return replacer.Replace(wDoc, contentControlTag);
+ }
+
+ ///
+ /// 替换图片
+ ///
+ /// Word文档对象
+ /// 要替换的控件tag
+ /// 新图片的路径
+ ///
+ public static bool ReplaceImage(WordprocessingDocument wDoc,
+ string contentControlTag,
+ byte[] imageBytes,
+ ImageFormat imageFormat,
+ string width = null,
+ string height = null)
+ {
+ var replacer = new ImageUpdater(imageBytes, imageFormat, width, height);
+ return replacer.Replace(wDoc, contentControlTag);
+ }
+
+ ///
+ /// 替换图片
+ ///
+ ///
+ ///
+ ///
+ private bool Replace(WordprocessingDocument wDoc, string contentControlTag)
+ {
+ var mainDocumentPart = wDoc.MainDocumentPart;
+ var mdXDoc = mainDocumentPart.GetXDocument();
+ var cc = mdXDoc.Descendants(W.sdt)
+ .FirstOrDefault(sdt => (string)sdt.Elements(W.sdtPr).Elements(W.tag).Attributes(W.val).FirstOrDefault() == contentControlTag);
+
+ if (cc != null)
+ {
+ // 替换imagePart
+ var imageId = (string)cc.Descendants(A.blip).Attributes(R.embed).FirstOrDefault();
+
+ if (imageId != null)
+ {
+ ImagePart imagePart = (ImagePart)mainDocumentPart.GetPartById(imageId);
+ ReplaceNewImage(imagePart, this.ImageBytes);
+ }
+
+ // 修改宽度和高度
+ UpdateImageMetrics(mdXDoc, cc);
+
+ // 替换cc
+ var paragraph = cc.Descendants(W.sdtContent).Descendants(W.p).FirstOrDefault();
+ if (paragraph != null)
+ {
+ cc.ReplaceWith(paragraph);
+ }
+
+ mainDocumentPart.PutXDocument();
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// 更新图片宽高
+ ///
+ ///
+ private void UpdateImageMetrics(XDocument mdXDoc, XElement cc)
+ {
+ float dpi = 96;
+
+ // 得到图片宽高
+ var imgStream = new MemoryStream(this.ImageBytes);
+ var (imgWidth, imgHeight) = ImageHelper.GetImageMetrics(imgStream, this._imageFormat);
+
+ // 得到页面宽高
+ double pageWidth = 0;
+ double pageHeight = 0;
+
+ var pageSize = mdXDoc.Descendants(W.sectPr).FirstOrDefault()?.Descendants(W.pgSz).FirstOrDefault();
+ if (pageSize != null)
+ {
+ pageWidth = Convert.ToDouble(pageSize.Attribute(W.w.GetName("w")).Value) / 20;
+ pageHeight = Convert.ToDouble(pageSize.Attribute(W.w.GetName("h")).Value) / 20;
+ }
+
+ // 得到设置宽高,传进来的参数
+ int.TryParse(this._width, out var settingWidth);
+ int.TryParse(this._height, out var settingHeight);
+
+ // 如果设置的宽度是百分比,那么按百分比计算宽度
+ if (this._width != null && this._width.EndsWith("%"))
+ {
+ // 先计算比例,避免宽度变更后比例也跟着变化。
+ var radio = imgWidth / (float)imgHeight;
+ double percent = Convert.ToDouble(this._width.TrimEnd('%')) / 100;
+ imgWidth = (int)(pageWidth * percent);
+
+ // 如果没有设置高度,那么按比例计算高度
+ if (this._height == null)
+ {
+ // 那么按比例计算高度
+ imgHeight = (int)(imgWidth / radio);
+ }
+ }
+ else if (settingWidth > 0) // 如果设置了宽度,那么按设置的宽度来
+ {
+ imgWidth = settingWidth;
+ }
+
+ // 如果度是百分比,那么按百分比计算高度
+ if (this._height != null && this._height.EndsWith("%"))
+ {
+ // 先计算比例,避免宽度变更后比例也跟着变化。
+ var radio = imgWidth / (float)imgHeight;
+ double percent = Convert.ToDouble(this._height.TrimEnd('%')) / 100;
+ imgHeight = (int)(pageHeight * percent);
+
+ // 如果没有设置宽度,那么按比例计算宽度
+ if (this._width == null)
+ {
+ // 那么按比例计算宽度
+ imgWidth = (int)(imgHeight * radio);
+ }
+ }
+ else if (settingHeight > 0) // 如果设置了高度,那么按设置的高度来
+ {
+ imgHeight = settingHeight;
+ }
+
+ // 换算成EMUS
+ var cx = (long)(imgWidth / dpi * 914400);
+ var cy = (long)(imgHeight / dpi * 914400);
+
+ var drawing = cc.Descendants(W.drawing).FirstOrDefault();
+ if (drawing != null)
+ {
+ var extent = drawing.Descendants(WP.extent).FirstOrDefault();
+ if (extent != null)
+ {
+ extent.SetAttributeValue("cx", cx);
+ extent.SetAttributeValue("cy", cy);
+ }
+ var aExtent = drawing.Descendants(A.graphic).Descendants(Pic.spPr).Descendants(A.ext).FirstOrDefault();
+ if (aExtent != null)
+ {
+ aExtent.SetAttributeValue("cx", cx);
+ aExtent.SetAttributeValue("cy", cy);
+ }
+ }
+ }
+
+ // 按比例缩放图片的方法,传入图片原始宽度和高度,传入缩放后的宽度
+ private static (int width, int height) ScaleImage(int originalWidth, int originalHeight, int scaledWidth)
+ {
+ var ratio = (float)originalWidth / originalHeight;
+ var scaledHeight = (int)(scaledWidth / ratio);
+ return (scaledWidth, scaledHeight);
+ }
+
+ ///
+ /// 替换新图片
+ ///
+ ///
+ ///
+ private void ReplaceNewImage(ImagePart imagePart, byte[] imageBytes)
+ {
+ var stream = imagePart.GetStream();
+
+ BinaryWriter writer = new BinaryWriter(stream);
+ writer.Write(imageBytes);
+ writer.Close();
+ }
+ }
+}
diff --git a/OpenXmlPowerTools/NugetPush.bat b/OpenXmlPowerTools/NugetPush.bat
new file mode 100644
index 00000000..33e81789
--- /dev/null
+++ b/OpenXmlPowerTools/NugetPush.bat
@@ -0,0 +1,4 @@
+del .\bin\Release\*.nupkg
+dotnet pack -o ./bin/release
+dotnet nuget push .\bin\Release\*.nupkg -k 123.123a -s http://nuget.cefcfco.com
+pause
\ No newline at end of file
diff --git a/OpenXmlPowerTools/OpenXmlPowerTools.csproj b/OpenXmlPowerTools/OpenXmlPowerTools.csproj
index c7220506..53c99d63 100644
--- a/OpenXmlPowerTools/OpenXmlPowerTools.csproj
+++ b/OpenXmlPowerTools/OpenXmlPowerTools.csproj
@@ -1,6 +1,12 @@
- net45;net46;netstandard2.0
+ netstandard2.0
+ 4.5.10.5
+ yitian.chen
+ yitian.chen
+ OpenXmlPowerTools-HrRd
+ true
+ True
diff --git a/OpenXmlPowerToolsExamples/ChartUpdater01/ChartUpdater01.cs b/OpenXmlPowerToolsExamples/ChartUpdater01/ChartUpdater01.cs
index 5811c0e4..cf4a2027 100644
--- a/OpenXmlPowerToolsExamples/ChartUpdater01/ChartUpdater01.cs
+++ b/OpenXmlPowerToolsExamples/ChartUpdater01/ChartUpdater01.cs
@@ -14,6 +14,46 @@ namespace OpenXmlPowerTools
class Program
{
static void Main(string[] args)
+ {
+ // Example1();
+ TowTypeChartExample();
+ }
+
+ private static void TowTypeChartExample()
+ {
+ var fi = new FileInfo("TowTypeChart.docx");
+
+ using (var wDoc = WordprocessingDocument.Open(fi.FullName, true))
+ {
+ var chart1Data = new ChartData
+ {
+ SecondChartType = C.lineChart,
+ SecondChartSeriesIndex = new[] { 1 },
+ SeriesNames = new[] {
+ "平仓手数",
+ "平仓盈亏-逐笔对冲",
+ },
+ CategoryDataType = ChartDataType.String,
+ CategoryNames = new[] {
+ "1:0天",
+ "1:1天",
+ "1:2天",
+ "1:3天",
+ },
+ Values = new double[][] {
+ new double[] {
+ 100, 310, 220, 450,
+ },
+ new double[] {
+ -11323.65, 3101, -12220, 15421,
+ },
+ },
+ };
+ ChartUpdater.UpdateChart(wDoc, "towTypeChart", chart1Data);
+ }
+ }
+
+ private static void Example1()
{
var n = DateTime.Now;
var tempDi = new DirectoryInfo(string.Format("ExampleOutput-{0:00}-{1:00}-{2:00}-{3:00}{4:00}{5:00}", n.Year - 2000, n.Month, n.Day, n.Hour, n.Minute, n.Second));
diff --git a/OpenXmlPowerToolsExamples/ChartUpdater01/ChartUpdater01.csproj b/OpenXmlPowerToolsExamples/ChartUpdater01/ChartUpdater01.csproj
index e188d465..5bd48a12 100644
--- a/OpenXmlPowerToolsExamples/ChartUpdater01/ChartUpdater01.csproj
+++ b/OpenXmlPowerToolsExamples/ChartUpdater01/ChartUpdater01.csproj
@@ -12,4 +12,10 @@
+
+
+
+ Always
+
+
\ No newline at end of file
diff --git a/OpenXmlPowerToolsExamples/ChartUpdater01/TowTypeChart.docx b/OpenXmlPowerToolsExamples/ChartUpdater01/TowTypeChart.docx
new file mode 100644
index 00000000..5e4ae532
Binary files /dev/null and b/OpenXmlPowerToolsExamples/ChartUpdater01/TowTypeChart.docx differ
diff --git a/OpenXmlPowerToolsExamples/DocumentAssembler02/Data.xml b/OpenXmlPowerToolsExamples/DocumentAssembler02/Data.xml
index 64cc21e5..2ab6983a 100644
--- a/OpenXmlPowerToolsExamples/DocumentAssembler02/Data.xml
+++ b/OpenXmlPowerToolsExamples/DocumentAssembler02/Data.xml
@@ -15,4 +15,21 @@
September 26, 2001
+
+ -
+ Items1
+ 1
+ 10
+
+ -
+ Items2
+ 2
+ 15
+
+ -
+ Items3
+ 3
+ 30
+
+
\ No newline at end of file
diff --git a/OpenXmlPowerToolsExamples/DocumentAssembler02/TemplateDocument.docx b/OpenXmlPowerToolsExamples/DocumentAssembler02/TemplateDocument.docx
index 45e8c994..3b45793a 100644
Binary files a/OpenXmlPowerToolsExamples/DocumentAssembler02/TemplateDocument.docx and b/OpenXmlPowerToolsExamples/DocumentAssembler02/TemplateDocument.docx differ
diff --git a/OpenXmlPowerToolsExamples/DocumentBuilder01/DocumentBuilder01.csproj b/OpenXmlPowerToolsExamples/DocumentBuilder01/DocumentBuilder01.csproj
index e188d465..5f593cb0 100644
--- a/OpenXmlPowerToolsExamples/DocumentBuilder01/DocumentBuilder01.csproj
+++ b/OpenXmlPowerToolsExamples/DocumentBuilder01/DocumentBuilder01.csproj
@@ -3,6 +3,9 @@
Exe
net45;net46;netcoreapp2.0
+
+
+
diff --git a/OpenXmlPowerToolsExamples/MarkupSimplifierApp/MarkupSimplifierApp.csproj b/OpenXmlPowerToolsExamples/MarkupSimplifierApp/MarkupSimplifierApp.csproj
index 90ae7ebe..ff153d40 100644
--- a/OpenXmlPowerToolsExamples/MarkupSimplifierApp/MarkupSimplifierApp.csproj
+++ b/OpenXmlPowerToolsExamples/MarkupSimplifierApp/MarkupSimplifierApp.csproj
@@ -15,9 +15,7 @@
-
- Form
-
+
Form