在 OpenXML 里的图表存放的日期时间很多存放的是数值,需要进行转换才能获取到用户可见的字符串

日期在 OpenXML 里可以使用数值存放,需要根据数值和格式化字符串转换为用户可见的字符串

如以下的 PPT 文件

存储的代码如下

  <c:cat>
<c:numRef>
<c:f>Sheet1!$A$2:$A$6</c:f>
<c:numCache>
<c:formatCode>m/d/yyyy</c:formatCode>
<c:ptCount val="5" />
<c:pt idx="0">
<c:v>37261</c:v>
</c:pt>
<c:pt idx="1">
<c:v>37262</c:v>
</c:pt>
<c:pt idx="2">
<c:v>37263</c:v>
</c:pt>
<c:pt idx="3">
<c:v>37264</c:v>
</c:pt>
<c:pt idx="4">
<c:v>37265</c:v>
</c:pt>
</c:numCache>
</c:numRef>
</c:cat>

本文将告诉大家如何从上面的数据转换为日期字符串

本文基于 dotnet OpenXML 解析 PPT 图表 面积图入门 的内容,替换了 PPT 文档。可以从本文最后获取到测试的文件和所有代码

在以上的测试的文档,类别的内容是日期,存储代码如上。在开始解析之前,需要了解 PPT 的图表的日期存放格式。这个存放格式有两套,分别是使用 1904 作为基础和使用 1900 作为基础的时间,和 Excel 存储日期相同,请看 Date systems in Excel

为了了解当前的图表采用的基础时间,先读取 ChartSpace 的 Date1904 属性,如以下代码

var useDate1904 = chartSpace.Date1904?.Val?.Value ?? false;

根据 ECMA 376 的第 21.2.2.38 章的描述,在 Date1904 属性设置为 true 时,将采用 1904 作为基础的日期。计算方法是使用 1904 或 1900 的前一天,分别是 1903.12.31 和 1899.12.31 作为计算。存放的数值表示的是加上当前的天数,计算到日期字符串,需要减去当天

在获取到 NumericValue 的值,如以下代码的 numericValueText 可以进行计算

  if (numericValueText != null && double.TryParse(numericValueText, out var value))
{
var days = value;
days--; // 不包括当天 // 这里只格式化日期的
// This element specifies that the chart uses the 1904 date system. If the 1904 date system is used, then all dates
// and times shall be specified as a decimal number of days since Dec. 31, 1903. If the 1904 date system is not
// used, then all dates and times shall be specified as a decimal number of days since Dec. 31, 1899.
var useDate1904 = chartSpace.Date1904?.Val?.Value ?? false;
if (useDate1904)
{
list.Add(new DateTime(1903, 12, 31).AddDays(days).ToString(format));
}
else
{
list.Add(new DateTime(1899, 12, 31).AddDays(days).ToString(format));
}
}

以上的 format 是格式化字符串,格式化字符串可以用来告诉软件如何格式化日期等内容

在 NumberingCache 存在格式化字符串的定义,如不写将不进行格式化。在 NumberingCache 的每个 NumericPoint 也可以存放格式化字符串,给每个数值定义格式化字符串。如果 NumericPoint 没有定义,将继承使用 NumberingCache 的格式化字符串,如以下代码,获取类别的数值定义的格式化字符串

    // 读取缓存
var categoryAxisDataNumberingCache = categoryAxisDataNumberReference
.GetFirstChild<DocumentFormat.OpenXml.Drawing.Charts.NumberingCache>()!;
// 字符串格式化方式,例如日期方式格式化,可以是空,空表示不需要格式化
var formatCodeText = categoryAxisDataNumberingCache.FormatCode?.Text; foreach (var numericPoint in categoryAxisDataNumberingCache
.Elements<DocumentFormat.OpenXml.Drawing.Charts.NumericPoint>())
{
var numericPointFormatCode = numericPoint.FormatCode;
var numericPointFormatCodeText = numericPointFormatCode?.Value ?? formatCodeText;
}

以上代码的 numericPointFormatCodeText 就是格式化字符串的内容

在 PPT 里,对于日期,如果格式化字符串是默认的字符串,将采用所运行的设备的语言文化进行格式化。例如在使用中文的设备上运行 PPT 软件,将使用 yyyy/M/d 作为默认的格式化

如在使用中文的设备,需要使用以下代码进行处理

  var format = numericPointFormatCodeText;
if (format == null || format == "m/d/yyyy")
{
// 如果是空和默认的,转换为中文的。后续可以根据设备的语言,转换为对应的日期
format = "yyyy/M/d";
}

将以上的代码组合,即可解析图表类别的日期内容

  // 类别轴上的数据 横坐标轴上的数据
var categoryAxisData =
areaChartSeries.GetFirstChild<DocumentFormat.OpenXml.Drawing.Charts.CategoryAxisData>()!;
// 类别轴上的数据 横坐标轴上的数据 可能是数据,也就是 NumberReference 类型。也可能是字符串,也就是 StringReference 类型。这份课件里面,存放的是 NumberReference 类型,以下代码只演示采用 NumberReference 类型的读取方式,还请在具体项目,自行判断
// 以下是 NumberReference 类型读取的例子
var categoryAxisDataNumberReference = categoryAxisData
.GetFirstChild<DocumentFormat.OpenXml.Drawing.Charts.NumberReference>();
if (categoryAxisDataNumberReference != null)
{
// 这个公式表示是从 Excel 哪个数据获取的,获取的方式比较复杂。这里还是先从缓存获取
var categoryAxisDataFormula = categoryAxisDataNumberReference
.GetFirstChild<DocumentFormat.OpenXml.Drawing.Charts.Formula>(); // 读取缓存
var categoryAxisDataNumberingCache = categoryAxisDataNumberReference
.GetFirstChild<DocumentFormat.OpenXml.Drawing.Charts.NumberingCache>()!;
// 字符串格式化方式,例如日期方式格式化,可以是空,空表示不需要格式化
var formatCodeText = categoryAxisDataNumberingCache.FormatCode?.Text; var list = new List<string>(); foreach (var numericPoint in categoryAxisDataNumberingCache
.Elements<DocumentFormat.OpenXml.Drawing.Charts.NumericPoint>())
{
var numericPointFormatCode = numericPoint.FormatCode;
var numericPointFormatCodeText = numericPointFormatCode?.Value ?? formatCodeText; var numericValueText = numericPoint.NumericValue?.Text; var format = numericPointFormatCodeText;
if (format == null || format == "m/d/yyyy")
{
// 如果是空和默认的,转换为中文的。后续可以根据设备的语言,转换为对应的日期
format = "yyyy/M/d";
} if (numericValueText != null && double.TryParse(numericValueText, out var value))
{
var days = value;
days--; // 不包括当天 // 这里只格式化日期的
// This element specifies that the chart uses the 1904 date system. If the 1904 date system is used, then all dates
// and times shall be specified as a decimal number of days since Dec. 31, 1903. If the 1904 date system is not
// used, then all dates and times shall be specified as a decimal number of days since Dec. 31, 1899.
// [Date systems in Excel](https://support.microsoft.com/en-us/office/date-systems-in-excel-e7fe7167-48a9-4b96-bb53-5612a800b487 )
var useDate1904 = chartSpace.Date1904?.Val?.Value ?? false;
if (useDate1904)
{
list.Add(new DateTime(1903, 12, 31).AddDays(days).ToString(format));
}
else
{
list.Add(new DateTime(1899, 12, 31).AddDays(days).ToString(format));
}
}
else
{
list.Add(numericValueText ?? string.Empty);
}
}
}

以上代码的 list 集合就存放了类别的内容

运行的效果如下

本文以上的测试文件和代码放在githubgitee 欢迎访问

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 9edb86c15c3f7c9aff9896ffc2de903464b2feb7

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git

获取代码之后,进入 MainWindow.xaml.cs 文件,在这个文件里就是本文的例子代码

更多请看 Office 使用 OpenXML SDK 解析文档博客目录

dotnet OpenXML 解析 PPT 图表 解析日期时间表示内容的更多相关文章

  1. dotnet OpenXML 读取 PPT 内嵌 ole 格式 Excel 表格的信息

    在 Office 中,可以在 PPT 里面插入表格,插入表格有好多不同的方法,对应 OpenXML 文档存储的更多不同的方式.本文来介绍如何读取 PPT 内嵌 ole 格式的 xls+ 表格的方法 在 ...

  2. vscode 用户代码片段 vue初始化模板 Snippet #新加入开头注释 自动生成文件名 开发日期时间等内容

    vue文件模板 模板变量 https://code.visualstudio.com/docs/editor/userdefinedsnippets#_variables vue.json { // ...

  3. C#中用DateTime的ParseExact方法解析日期时间(excel中使用系统默认的日期格式)

    最近做的项目中服务器是英文的系统,系统需要通过excel的单元格导入日期,excel中的日期格式是系统默认的日期格式,如下图所示 以上日期格式,会跟着操作系统设置的日期格式相同例如我的中文系统的日期格 ...

  4. 全面解析Java日期时间API

    时区 GMT(Greenwich Mean Time):格林尼治时间,格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时(也就是在格林尼治上空最高点时)的时间. UTC(Universal Time ...

  5. Java日期时间API系列21-----Jdk8中java.time包中的新的日期时间API类,xk-time时间转换,计算,格式化,解析的工具

    通过工作之余,对Java8中java.time包源码的不断学习,使用和总结,开发了xk-time,初步完成,欢迎试用和提出建议! xk-time xk-time is a datetime conve ...

  6. 解析php时间戳与日期的转换

    php中时间戳与日期的转换. 实现功能:获取某个日期的时间戳,或获取某个时间的PHP时间戳. strtotime能将任何英文文本的日期时间描述解析为Unix时间戳,我们结合mktime()或date( ...

  7. 解析MySQL中存储时间日期类型的选择问题

    解析MySQL中存储时间日期类型的选择问题_Mysql_脚本之家 https://www.jb51.net/article/125715.htm 一般应用中,我们用timestamp,datetime ...

  8. WPF解析PPT为图片

    偶遇需要解析 PPT为单张图片 其中,对于包含动画的PPT页,分别对动画最后效果进行截取,即每个连续动画截取 (动画N个)N+1(原图)张 http://git.oschina.net/jiailiu ...

  9. DELPHI解析JSON格式化的日期

    DELPHI解析JSON格式化的日期 json返回的日期是 /Date(1560355200000)/ 这样的格式. 这个1560355200000,是指1970年以后的秒数. DELPHI如何解析这 ...

  10. dotnet OpenXML 转换 PathFillModeValues 为颜色特效

    在 OpenXml 预设形状,有一些形状设置了 PathFillModeValues 枚举,此枚举提供了亮暗的蒙层特效.具体的特效是让形状选择一个画刷,在画刷上加上特效.如立体几何 Cube 形状,在 ...

随机推荐

  1. gRPC入门学习之旅(三)

    gRPC入门学习之旅(一) gRPC入门学习之旅(二) 2.3.创建自定义服务 除上面的模板中自带的一个gRPC服务之后,我们再创建一个自己的服务,我将创建一个用户信息gRPC服务,主要功能有三个,登 ...

  2. torch的cuda版本安装

    1.拥有英伟达显卡NVIDIA NVIDIA CUDA各版本下载链接(包括最新11版本和以往10.2版本) 以下是从NVIDIA官网转过来的链接,方便需要下载各种版本CUDA的同学.(借阅) http ...

  3. 立创EDA的使用

    立创EDA的使用 1.实验原理 最近在使用立创EDA来做电路作业,这里记录一下立创EDA的基本操作,以后小型的电路设计可以在其主页完成.立创EDA是一个可以线上完成电路设计仿真以及布线的免费设计工具, ...

  4. KingbaseES 原生XML系列五--XML关系表函数

    KingbaseES 原生XML系列五--XML关系表函数(QUERY_TO_XML,TABLE_TO_XML,XMLTABLE) XML的简单使其易于在任何应用程序中读写数据,这使XML很快成为数据 ...

  5. 【已解决】org.apache.thrift.transport.TTransportException: Could not create ServerSocket on address 0.0.0.0/0.0.0.0:9083.

    杀死这些进程 kill -9 进程号

  6. Apache服务器打开网页是乱码解决方案

    当 Apache 服务器显示乱码时,可以使用两种方法解决: 1. 服务器端 可以在 Apache 的配置文件中添加以下内容来设置默认编码为UTF-8: AddDefaultCharset utf-8 ...

  7. #KM算法#UVA11383 Golden Tiger Claw

    题目 给定 \(n*n\) 的矩阵,现在给每行安排一个权值 \(x_i\),给每列安排一个权值 \(y_j\), 使得 \(x_i+y_j\geq a_{i,j}\),并且使 \(\sum_{i=1} ...

  8. #期望dp#51nod 2015 诺德街

    题目传送门 分析 禁不住 QuantAsk 的诱惑(bushi) 考虑一条路线可以由若干段 \(1-2-\dots-n-\dots-2\) 以及 最后一段 \(1-\dots-x\) 组成. 对于最后 ...

  9. #bitset优化,莫队#洛谷 5355 [Ynoi2017] 由乃的玉米田

    没有除法的版本 弱化版Blog 题目 分析 只针对除法而言,如果商很大直接用bitset判断是否存在, 否则直接预处理最近的答案判断是否在区间内即可,注意0要特判 代码 #include <cs ...

  10. Java break、continue 详解与数组深入解析:单维数组和多维数组详细教程

    Java Break 和 Continue Java Break: break 语句用于跳出循环或 switch 语句. 在循环中使用 break 语句可以立即终止循环,并继续执行循环后面的代码. 在 ...