# OfficeXml
[迁移指南](./迁移指南.md)
## 概述
将 docx、pptx、xlsx 等文件中的 xml 转为 tsl 对象
```xml
最小申购、赎回单位
(份)
```
上述是一个 docx 中的段落的 xml,序列化为 tsl 过程如下
```go
uses DocxML; // 上述xml属于DocxML
p := new P(); // 创建一个P对象(段落w:p)
p.Init(node); // 假设node节点是上面的xml指向的Node对象
p.Deserialize(); // 将node对象的xml序列化到tsl对象
// 序列化完毕后,可直接对应取值
echo p.PPr.Jc.Val; // 输出:left
// 如果需要修改内容,通过Serialize()回写到node
p.PPr.Jc.Val := "center";
// 回写方法1,适合修改单个对象
p.PPr.Jc.Serialize();
// 回写方法2,大量修改,不同的对象
p.Serialize(); // 或p.PPr.Serialize()
// 在获取存在多个节点的对象时,比如上述的w:r对象是复数的,则需要通过Rs()获取
// 直接调用Rs()会获取所有的R对象,加上索引会获取第N+1个
echo p.Rs(1).T.Text; // 输出:(份)
```
## 基类
`OpenXmlAttribute`是节点的属性类
`OpenXmlElement.tsf`是节点基类
`OpenXmlSimpleType`是简单类型的元素节点类,继承于`OpenXmlElement`,如``
`OpenXmlTextElement`是包含文本内容的元素节点类,继承于`OpenXmlElement`,如`文本`
`OpenXmlCompositeElement`是复杂节点的元素节点类,继承于`OpenXmlElement`,会包含一系列的属性或其他元素节点类
## Unit 单元
- `DocxML`
包含`docx`文件独有的 xml 节点对象,一般 xml 的命名空间是`w`,如`w:p`
- `PptxML`
包含`pptx`文件独有的 xml 节点对象,一般 xml 的命名空间是`p`,如`p:spPr`
- `XlsxML`
包含`xlsx`文件独有的 xml 节点对象
- `DrawingML`
包含`docx,pptx,xlsx`文件图形的 xml 节点对象,一般 xml 的命名空间是`a`,如`a:xfrm`
- `SharedML`
包含`docx,pptx,xlsx`文件共有的 xml 节点对象
- `VML`
[参考链接 1](http://webapp.docx4java.org/OnlineDemo/ecma376/)
[参考链接 2](http://officeopenxml.com/index.php)
## 部件
### Components
一共有三个部件,分别是:
1. `DocxComponents.tsf`:docx 文件的各部分 xml 内容
2. `XlsxComponents`:xlsx 文件的各部分 xml 内容
3. `PptxComponents`:pptx 文件的各部分 xml 内容
以`DocxComponents.tsf`为例,使用这个类,可以获取到对应的 docx 文件的 xml 对象
```go
component := new DocxComponents(); // 创建对象
component.Open("", "xxx.docx"); // 打开文件
document := component.Document; // 获取document.xml,生成Document对象
document.Deserialize(); // 将xml对象的数据反序列化到tsl对象中
document.Body.Elements(); // 可以获取document的body下的所有对象列表
// 反序列化后,可进行读写
styles := component.Styles; // 获取styles.xml,生成Styles对象
```
document.xml 内容如下
```xml
分栏前
```
### 单位装饰器 UnitDecorator
每个对象都有一个单位装饰器,能统一转成磅(point)单位(如果有配置属性转换),还能保留原来的接口
每个`ML`都有装饰器`tsf`统一命名是`Unit的名称+UnitDecorator`,如`docx`(`docx`大部分`xml`隶属于`DocxML`)的`SectPr`对象的装饰器是`SectPrUnitDecorator`
如:有下面一段 xml,其中的`pgSz.w = "11906", pgSz.h = "16838"`都需要转换成 point
```xml
```
```go
uses DocxMLUnitDecorator;
component := new Components(); // 创建对象
component.Open("", "xxx.docx"); // 打开文件
document := component.Document; // 获取document.xml,生成Document对象
document.Deserialize(); // 将xml对象的数据反序列化到tsl对象中
sect_pr := document.Body.SectPr; // 获取SectPr对象
sect_pr_unit_decorator := new SectPrUnitDecorator(sect_pr); // 装饰器构造需要原本的对象
echo "w = ", sect_pr.PgSz.W; // 输出的是字符串,原本的单位是twips
echo "\n";
echo "w = ", sect_pr_unit_decorator.PgSz.W; // 此时输出的是数字类型,单位是point
```
### 适配器 Adapter
适配器是通过 key 获取对应的对象,比如样式可以通过样式 ID 获取对应的样式对象
只有部分对象才有适配器(具体可见`autounit/xxxMLAdapter`),比如`DocxML.Styles`的适配器是`StylesAdapter`
styles.xml 部分如下
```xml
```
```go
uses DocxMLAdapter;
component := new Components(); // 创建对象
component.Open("", "xxx.docx"); // 打开文件
document := component.Document; // 获取document.xml,生成Document对象
document.Deserialize(); // 将xml对象的数据反序列化到tsl对象中
styles := document.Styles;
// 现在需要通过styleId获取Style对象
styles_adapter := new StylesAdapter(styles);
// 通过StyleId获取Style对象
style := styles_adapter.GetStyleByStyleId("a6");
echo style.Name; // 输出的是"页脚 字符"
```
### 其他设计的补充
```xml
cos
```
由于设计取对象时候不包含前缀,那么同时存在多个`rPr`时,如何区分是哪一个?
取`m:rPr`时,可通过`r.RPr`,这是因为它们的前缀都是`m`,所以可直接获取
取`a:rPr`时,需要指定前缀`a`,通过`r.RPr('a')`,进行获取`RPr`对象
## TODO
- [ ] 命名空间不同,但是名字相同属性的读写访问
- [ ] 属性的删除操作