trackswap 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +322 -281
- package/dist/FIT/base.d.ts +0 -30
- package/dist/FIT/decoder.d.ts +0 -48
- package/dist/FIT/encoder.d.ts +0 -97
- package/dist/FIT/mesg.d.ts +0 -3
- package/dist/FIT/middleware.d.ts +0 -15
- package/dist/FIT/plugins.d.ts +0 -9
- package/dist/FIT/processor.d.ts +0 -24
- package/dist/FIT/types/mesg_num.d.ts +102 -102
- package/dist/FIT/types/sport.d.ts +44 -44
- package/dist/FIT/types.d.ts +0 -35
- package/dist/GPX/base.d.ts +0 -39
- package/dist/GPX/converters.d.ts +0 -30
- package/dist/GPX/decoder.d.ts +0 -66
- package/dist/GPX/encoder.d.ts +0 -109
- package/dist/GPX/middleware.d.ts +0 -9
- package/dist/GPX/processor.d.ts +0 -18
- package/dist/GPX/types.d.ts +0 -108
- package/dist/TCX/base.d.ts +0 -33
- package/dist/TCX/converters.d.ts +0 -24
- package/dist/TCX/decoder.d.ts +0 -54
- package/dist/TCX/encoder.d.ts +0 -109
- package/dist/TCX/index.d.ts +4 -1
- package/dist/TCX/middleware.d.ts +0 -9
- package/dist/TCX/processor.d.ts +0 -18
- package/dist/TCX/types.d.ts +0 -13
- package/dist/TrackSwap.d.ts +37 -33
- package/dist/core/base.d.ts +0 -46
- package/dist/core/xml-utils.d.ts +0 -24
- package/dist/index.js +24 -5
- package/dist/sport/base.d.ts +63 -0
- package/dist/sport/converters.d.ts +33 -0
- package/dist/sport/encoders.d.ts +34 -0
- package/dist/sport/index.d.ts +17 -0
- package/dist/sport/processor.d.ts +19 -0
- package/dist/types.d.ts +91 -13
- package/package.json +18 -3
- package/dist/FIT/base.js +0 -101
- package/dist/FIT/crc.js +0 -16
- package/dist/FIT/decoder.js +0 -323
- package/dist/FIT/encoder.js +0 -445
- package/dist/FIT/index.js +0 -13
- package/dist/FIT/mesg.js +0 -208
- package/dist/FIT/middleware.js +0 -206
- package/dist/FIT/plugins.js +0 -104
- package/dist/FIT/processor.js +0 -170
- package/dist/FIT/types/course_point.js +0 -58
- package/dist/FIT/types/event.js +0 -50
- package/dist/FIT/types/event_type.js +0 -19
- package/dist/FIT/types/file.js +0 -24
- package/dist/FIT/types/index.js +0 -297
- package/dist/FIT/types/mesg_num.js +0 -106
- package/dist/FIT/types/sport.js +0 -48
- package/dist/FIT/types.js +0 -1
- package/dist/FIT/util.js +0 -7
- package/dist/GPX/base.js +0 -56
- package/dist/GPX/converters.js +0 -352
- package/dist/GPX/decoder.js +0 -409
- package/dist/GPX/encoder.js +0 -513
- package/dist/GPX/extensions/index.js +0 -14
- package/dist/GPX/index.js +0 -11
- package/dist/GPX/middleware.js +0 -93
- package/dist/GPX/processor.js +0 -188
- package/dist/GPX/types.js +0 -1
- package/dist/GPX/util.js +0 -18
- package/dist/TCX/base.js +0 -62
- package/dist/TCX/converters.js +0 -333
- package/dist/TCX/decoder.js +0 -350
- package/dist/TCX/encoder.js +0 -513
- package/dist/TCX/index.js +0 -9
- package/dist/TCX/middleware.js +0 -93
- package/dist/TCX/processor.js +0 -197
- package/dist/TCX/types.js +0 -1
- package/dist/TrackSwap.js +0 -84
- package/dist/core/base.js +0 -138
- package/dist/core/decoder.d.ts +0 -66
- package/dist/core/decoder.js +0 -90
- package/dist/core/index.js +0 -4
- package/dist/core/processor.d.ts +0 -69
- package/dist/core/processor.js +0 -265
- package/dist/core/xml-utils.js +0 -140
- package/dist/types.js +0 -1
package/dist/GPX/decoder.js
DELETED
|
@@ -1,409 +0,0 @@
|
|
|
1
|
-
import { BoundsConverter, CopyrightConverter, EmailConverter, LinkConverter, MetadataConverter, PersonConverter, RteConverter, TrkConverter, TrksegConverter, WptConverter, } from "./converters.js";
|
|
2
|
-
import { AstGenerateProcessor, CompleteProcessor, ConvertProcessor, TokenizeProcessor, PipelineStage, } from "./processor.js";
|
|
3
|
-
// ============ 主解码器类 ============
|
|
4
|
-
/**
|
|
5
|
-
* GPX解码器主类
|
|
6
|
-
*/
|
|
7
|
-
export class GPXDecoder {
|
|
8
|
-
constructor() {
|
|
9
|
-
this.converterPlugins = new Map();
|
|
10
|
-
this.registeredPlugins = new Set(); // 跟踪已注册的插件名
|
|
11
|
-
this.middlewarePlugins = [];
|
|
12
|
-
this.processors = []; // 固定的核心处理器
|
|
13
|
-
this.initialized = false;
|
|
14
|
-
this.defaultConvertersRegistered = false;
|
|
15
|
-
this.initializePipeline();
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* 初始化流水线 - 注册固定的核心处理器
|
|
19
|
-
*/
|
|
20
|
-
initializePipeline() {
|
|
21
|
-
// 固定的核心处理器,不允许用户修改
|
|
22
|
-
this.processors = [
|
|
23
|
-
new TokenizeProcessor(),
|
|
24
|
-
new AstGenerateProcessor(),
|
|
25
|
-
new ConvertProcessor((tag) => this.getConverter(tag)),
|
|
26
|
-
new CompleteProcessor(),
|
|
27
|
-
];
|
|
28
|
-
console.log("🔧 核心流水线处理器已初始化 (固定不可修改)");
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* 自动注册默认转换器 - 处理标准GPX标签
|
|
32
|
-
*/
|
|
33
|
-
async registerDefaultConverters() {
|
|
34
|
-
if (this.defaultConvertersRegistered)
|
|
35
|
-
return;
|
|
36
|
-
const defaultConverters = [
|
|
37
|
-
new WptConverter(),
|
|
38
|
-
new RteConverter(),
|
|
39
|
-
new TrkConverter(),
|
|
40
|
-
new TrksegConverter(),
|
|
41
|
-
new LinkConverter(),
|
|
42
|
-
new MetadataConverter(),
|
|
43
|
-
new PersonConverter(),
|
|
44
|
-
new EmailConverter(),
|
|
45
|
-
new CopyrightConverter(),
|
|
46
|
-
new BoundsConverter(),
|
|
47
|
-
];
|
|
48
|
-
for (const converter of defaultConverters) {
|
|
49
|
-
// 内部注册,不显示日志避免干扰
|
|
50
|
-
converter.supportedTags?.forEach((tag) => {
|
|
51
|
-
this.addConverterForTag(tag, converter);
|
|
52
|
-
});
|
|
53
|
-
this.registeredPlugins.add(converter.name);
|
|
54
|
-
}
|
|
55
|
-
this.defaultConvertersRegistered = true;
|
|
56
|
-
console.log("✅ 默认GPX转换器已自动注册 (wpt, rte, trk, metadata等)");
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* 为指定标签添加转换器,按优先级排序
|
|
60
|
-
*/
|
|
61
|
-
addConverterForTag(tag, converter) {
|
|
62
|
-
if (!this.converterPlugins.has(tag)) {
|
|
63
|
-
this.converterPlugins.set(tag, []);
|
|
64
|
-
}
|
|
65
|
-
const converters = this.converterPlugins.get(tag);
|
|
66
|
-
converters.push(converter);
|
|
67
|
-
// 按优先级排序(数字越小优先级越高)
|
|
68
|
-
converters.sort((a, b) => (a.priority || 100) - (b.priority || 100));
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* 注册转换器插件
|
|
72
|
-
*/
|
|
73
|
-
async registerConverter(plugin) {
|
|
74
|
-
// 检查插件是否已注册
|
|
75
|
-
if (this.registeredPlugins.has(plugin.name)) {
|
|
76
|
-
throw new Error(`转换器插件 ${plugin.name} 已存在`);
|
|
77
|
-
}
|
|
78
|
-
// 注册支持的标签(允许多个转换器处理同一标签)
|
|
79
|
-
plugin.supportedTags?.forEach((tag) => {
|
|
80
|
-
this.addConverterForTag(tag, plugin);
|
|
81
|
-
});
|
|
82
|
-
this.registeredPlugins.add(plugin.name);
|
|
83
|
-
// 显示优先级信息
|
|
84
|
-
const priorityInfo = plugin.priority !== undefined ? ` (优先级: ${plugin.priority})` : "";
|
|
85
|
-
console.log(`📦 已注册自定义转换器: ${plugin.name}${priorityInfo}, 支持标签: ${plugin.supportedTags?.join(", ")}`);
|
|
86
|
-
// 显示标签的转换器优先级顺序
|
|
87
|
-
plugin.supportedTags?.forEach((tag) => {
|
|
88
|
-
const converters = this.converterPlugins.get(tag) || [];
|
|
89
|
-
const converterNames = converters.map((c) => `${c.name}(${c.priority || 100})`);
|
|
90
|
-
console.log(` 📋 标签 "${tag}" 转换器优先级: ${converterNames.join(" > ")}`);
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* 注册中间件插件 - 真正的扩展点
|
|
95
|
-
*/
|
|
96
|
-
async registerMiddleware(plugin) {
|
|
97
|
-
const existingIndex = this.middlewarePlugins.findIndex((p) => p.name === plugin.name);
|
|
98
|
-
if (existingIndex !== -1) {
|
|
99
|
-
this.middlewarePlugins[existingIndex] = plugin;
|
|
100
|
-
console.log(`🔄 已更新中间件: ${plugin.name}`);
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
this.middlewarePlugins.push(plugin);
|
|
104
|
-
console.log(`🔌 已注册中间件: ${plugin.name}`);
|
|
105
|
-
}
|
|
106
|
-
// 显示中间件支持的钩子
|
|
107
|
-
const hooks = [];
|
|
108
|
-
if (plugin.onTokenize)
|
|
109
|
-
hooks.push("onTokenize");
|
|
110
|
-
if (plugin.onAstGenerate)
|
|
111
|
-
hooks.push("onAstGenerate");
|
|
112
|
-
if (plugin.onConvert)
|
|
113
|
-
hooks.push("onConvert");
|
|
114
|
-
if (plugin.onComplete)
|
|
115
|
-
hooks.push("onComplete");
|
|
116
|
-
if (plugin.onError)
|
|
117
|
-
hooks.push("onError");
|
|
118
|
-
if (hooks.length > 0) {
|
|
119
|
-
console.log(` 🎣 支持的钩子: ${hooks.join(", ")}`);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* 获取转换器(返回优先级最高的)
|
|
124
|
-
*/
|
|
125
|
-
getConverter(tag) {
|
|
126
|
-
const converters = this.converterPlugins.get(tag);
|
|
127
|
-
return converters && converters.length > 0 ? converters[0] : undefined;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* 获取指定标签的所有转换器(按优先级排序)
|
|
131
|
-
*/
|
|
132
|
-
getAllConverters(tag) {
|
|
133
|
-
return this.converterPlugins.get(tag) || [];
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* 移除转换器
|
|
137
|
-
*/
|
|
138
|
-
unregisterConverter(pluginName) {
|
|
139
|
-
// 找到插件实例
|
|
140
|
-
let pluginToRemove;
|
|
141
|
-
for (const [tag, converters] of this.converterPlugins) {
|
|
142
|
-
const index = converters.findIndex((plugin) => plugin.name === pluginName);
|
|
143
|
-
if (index !== -1) {
|
|
144
|
-
pluginToRemove = converters[index];
|
|
145
|
-
converters.splice(index, 1);
|
|
146
|
-
// 如果该标签没有转换器了,删除整个条目
|
|
147
|
-
if (converters.length === 0) {
|
|
148
|
-
this.converterPlugins.delete(tag);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
if (!pluginToRemove) {
|
|
153
|
-
console.warn(`转换器插件 ${pluginName} 不存在`);
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
this.registeredPlugins.delete(pluginName);
|
|
157
|
-
console.log(`🗑️ 已移除转换器: ${pluginName}`);
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* 移除中间件
|
|
161
|
-
*/
|
|
162
|
-
unregisterMiddleware(name) {
|
|
163
|
-
const index = this.middlewarePlugins.findIndex((p) => p.name === name);
|
|
164
|
-
if (index !== -1) {
|
|
165
|
-
this.middlewarePlugins.splice(index, 1);
|
|
166
|
-
console.log(`🗑️ 已移除中间件: ${name}`);
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
console.warn(`中间件 ${name} 不存在`);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* 列出所有已注册的转换器标签
|
|
174
|
-
*/
|
|
175
|
-
listConverters() {
|
|
176
|
-
return Array.from(this.converterPlugins.keys());
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* 列出所有已注册的转换器插件
|
|
180
|
-
*/
|
|
181
|
-
listConverterPlugins() {
|
|
182
|
-
return Array.from(this.registeredPlugins);
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* 列出所有已注册的中间件
|
|
186
|
-
*/
|
|
187
|
-
listMiddlewares() {
|
|
188
|
-
return this.middlewarePlugins.map((p) => p.name);
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* 列出核心处理器(只读)
|
|
192
|
-
*/
|
|
193
|
-
listProcessors() {
|
|
194
|
-
return this.processors.map((p) => p.constructor.name);
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* 获取标签的转换器详情(包括优先级信息)
|
|
198
|
-
*/
|
|
199
|
-
getConverterDetails(tag) {
|
|
200
|
-
const result = {};
|
|
201
|
-
if (tag) {
|
|
202
|
-
const converters = this.converterPlugins.get(tag);
|
|
203
|
-
if (converters) {
|
|
204
|
-
result[tag] = converters.map((c) => ({
|
|
205
|
-
name: c.name,
|
|
206
|
-
priority: c.priority || 100,
|
|
207
|
-
}));
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
else {
|
|
211
|
-
for (const [tagName, converters] of this.converterPlugins) {
|
|
212
|
-
result[tagName] = converters.map((c) => ({
|
|
213
|
-
name: c.name,
|
|
214
|
-
priority: c.priority || 100,
|
|
215
|
-
}));
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
return result;
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* 获取中间件详情(包括支持的钩子)
|
|
222
|
-
*/
|
|
223
|
-
getMiddlewareDetails() {
|
|
224
|
-
return this.middlewarePlugins.map((plugin) => {
|
|
225
|
-
const hooks = [];
|
|
226
|
-
if (plugin.onTokenize)
|
|
227
|
-
hooks.push("onTokenize");
|
|
228
|
-
if (plugin.onAstGenerate)
|
|
229
|
-
hooks.push("onAstGenerate");
|
|
230
|
-
if (plugin.onConvert)
|
|
231
|
-
hooks.push("onConvert");
|
|
232
|
-
if (plugin.onComplete)
|
|
233
|
-
hooks.push("onComplete");
|
|
234
|
-
if (plugin.onError)
|
|
235
|
-
hooks.push("onError");
|
|
236
|
-
return {
|
|
237
|
-
name: plugin.name,
|
|
238
|
-
hooks,
|
|
239
|
-
};
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
/**
|
|
243
|
-
* 初始化解码器
|
|
244
|
-
*/
|
|
245
|
-
async initialize() {
|
|
246
|
-
if (this.initialized)
|
|
247
|
-
return;
|
|
248
|
-
// 首先注册默认转换器
|
|
249
|
-
await this.registerDefaultConverters();
|
|
250
|
-
const context = this.createContext();
|
|
251
|
-
// 初始化所有插件
|
|
252
|
-
const allPlugins = [
|
|
253
|
-
...Array.from(this.converterPlugins.values()).flat(),
|
|
254
|
-
...this.middlewarePlugins,
|
|
255
|
-
];
|
|
256
|
-
for (const plugin of allPlugins) {
|
|
257
|
-
try {
|
|
258
|
-
await plugin.initialize?.(context);
|
|
259
|
-
}
|
|
260
|
-
catch (error) {
|
|
261
|
-
console.error(`插件 ${plugin.name} 初始化失败:`, error);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
this.initialized = true;
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* 销毁解码器
|
|
268
|
-
*/
|
|
269
|
-
async destroy() {
|
|
270
|
-
if (!this.initialized)
|
|
271
|
-
return;
|
|
272
|
-
const context = this.createContext();
|
|
273
|
-
// 销毁所有插件
|
|
274
|
-
const allPlugins = [
|
|
275
|
-
...Array.from(this.converterPlugins.values()).flat(),
|
|
276
|
-
...this.middlewarePlugins,
|
|
277
|
-
];
|
|
278
|
-
for (const plugin of allPlugins) {
|
|
279
|
-
try {
|
|
280
|
-
await plugin.destroy?.(context);
|
|
281
|
-
}
|
|
282
|
-
catch (error) {
|
|
283
|
-
console.error(`插件 ${plugin.name} 销毁失败:`, error);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
this.initialized = false;
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* 创建解码上下文
|
|
290
|
-
*/
|
|
291
|
-
createContext() {
|
|
292
|
-
return {
|
|
293
|
-
metadata: new Map(),
|
|
294
|
-
errors: [],
|
|
295
|
-
warnings: [],
|
|
296
|
-
stats: {
|
|
297
|
-
startTime: Date.now(),
|
|
298
|
-
processedTokens: 0,
|
|
299
|
-
convertedElements: 0,
|
|
300
|
-
},
|
|
301
|
-
performance: {
|
|
302
|
-
startTime: Date.now(),
|
|
303
|
-
},
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* 执行中间件钩子
|
|
308
|
-
*/
|
|
309
|
-
async executeMiddlewareHook(hookName, data, context) {
|
|
310
|
-
let result = data;
|
|
311
|
-
for (const middleware of this.middlewarePlugins) {
|
|
312
|
-
const hook = middleware[hookName];
|
|
313
|
-
if (hook) {
|
|
314
|
-
try {
|
|
315
|
-
result = (await hook.call(middleware, result, context)) || result;
|
|
316
|
-
}
|
|
317
|
-
catch (error) {
|
|
318
|
-
context.errors.push(error);
|
|
319
|
-
await middleware.onError?.(error, context);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
return result;
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* 主解析方法 - 固定的流水线 + 灵活的中间件
|
|
327
|
-
*/
|
|
328
|
-
async parserByBuffer(buffer) {
|
|
329
|
-
await this.initialize();
|
|
330
|
-
let context = this.createContext();
|
|
331
|
-
context.rawData = buffer;
|
|
332
|
-
context.xmlContent = buffer.toString("utf-8");
|
|
333
|
-
// 在上下文中传递解码器实例引用
|
|
334
|
-
context.metadata.set("decoder", this);
|
|
335
|
-
try {
|
|
336
|
-
// 固定的流水线阶段顺序执行
|
|
337
|
-
for (const processor of this.processors) {
|
|
338
|
-
try {
|
|
339
|
-
// 1. 执行核心处理器
|
|
340
|
-
context = await processor.process(context);
|
|
341
|
-
// 2. 根据阶段执行对应的中间件钩子
|
|
342
|
-
switch (processor.stage) {
|
|
343
|
-
case PipelineStage.TOKENIZE:
|
|
344
|
-
if (context.tokens) {
|
|
345
|
-
context.tokens = await this.executeMiddlewareHook("onTokenize", context.tokens, context);
|
|
346
|
-
}
|
|
347
|
-
break;
|
|
348
|
-
case PipelineStage.AST_GENERATE:
|
|
349
|
-
if (context.ast) {
|
|
350
|
-
context.ast = await this.executeMiddlewareHook("onAstGenerate", context.ast, context);
|
|
351
|
-
}
|
|
352
|
-
break;
|
|
353
|
-
case PipelineStage.CONVERT:
|
|
354
|
-
if (context.result) {
|
|
355
|
-
context.result = await this.executeMiddlewareHook("onConvert", context.result, context);
|
|
356
|
-
}
|
|
357
|
-
break;
|
|
358
|
-
case PipelineStage.COMPLETE:
|
|
359
|
-
if (context.result) {
|
|
360
|
-
context.result = await this.executeMiddlewareHook("onComplete", context.result, context);
|
|
361
|
-
}
|
|
362
|
-
break;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
catch (error) {
|
|
366
|
-
context.errors.push(error);
|
|
367
|
-
// 执行错误处理中间件
|
|
368
|
-
for (const middleware of this.middlewarePlugins) {
|
|
369
|
-
await middleware.onError?.(error, context);
|
|
370
|
-
}
|
|
371
|
-
console.error(`流水线阶段 ${processor.stage} 处理失败:`, error);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
return context.result;
|
|
375
|
-
}
|
|
376
|
-
catch (error) {
|
|
377
|
-
console.error("GPX解析失败:", error);
|
|
378
|
-
throw error;
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
/**
|
|
382
|
-
* 转换Extensions(向后兼容)
|
|
383
|
-
*/
|
|
384
|
-
convertExtensions(extensionsAST) {
|
|
385
|
-
const extensions = {};
|
|
386
|
-
const { attributes, tag, value } = extensionsAST;
|
|
387
|
-
// 处理属性
|
|
388
|
-
if (attributes) {
|
|
389
|
-
Object.entries(attributes).forEach(([key, value]) => {
|
|
390
|
-
extensions[key] = value;
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
// 如果有子节点,直接处理子节点,不再包装外层标签
|
|
394
|
-
if (extensionsAST?.children?.length) {
|
|
395
|
-
extensionsAST.children?.forEach((child) => {
|
|
396
|
-
extensions[child.tag] =
|
|
397
|
-
this.convertExtensions(child);
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
else if (value !== undefined) {
|
|
401
|
-
// 如果没有子节点但有值,直接返回值
|
|
402
|
-
return value;
|
|
403
|
-
}
|
|
404
|
-
return extensions;
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
export default {
|
|
408
|
-
GPXDecoder,
|
|
409
|
-
};
|