当我们把Open edX用于spoc中,可能会有这样一种需求:如何将既有课程尽可能自动化得导入到Open edX中

我想到比较好的一种策略是采用Open edX的Open Learning XML (OLX) 来做这件事

Open Learning XML (OLX)

Open Learning XML给出了一套课程文本化的描述,采用Open Learning XML,我们可以采用xml来定义我们的课程,从而做到在不使用edX Studio的情况下我们也能制作出所需的课程

课程的组成结构和元素在Open Learning XML都有相应描述,参考这些描述,你可以通过任何程序/语言生成所需的课程内容,之后导入到Open edX即可

OLX的功能

顺便我们也援引一下官方对OLX功能的描述

  • 在不同的Open edx实例网站中迁移课程
  • 在studio外部创建课程,包括转化自不同格式的内容
  • 保证内容格式的开放性和可移植性

OLX与跨平台导课

假设学校已有一套采用Java语言写成的教学系统,现在我们想使用Open edX,而不想废弃既有平台的课程,那么一般的做法是认为地将课程进行转化,如果课程数量庞大,这项工作就极其耗时

需要说明的是,由于平台特性上的差异,在转化之前你应当尽可能理解两个平台的特性,然后你作为一个“翻译者”,将内容形式进行转化,这部分的工作,机器无法帮到你,需要你花时间去理解课程结构,理解之后,你就可以开始将旧平台的课程,导出为OLX结构的文档,之后导入到Open edX平台中

OLX入门

如果官方能把create new repo的时间用来好好写文档,那么这部分本该很完备的

然而由于跳票的习惯,这部分也只是有个大纲,并没有内容,所有需要我们自力更生

课程结构

关于课程结构可以参考这个文档OLX Course Structure

demo

文档枯燥,我们还是那一个课程demo来遛一遛吧,可以Example of an OLX Course,习惯阅读英文的话,可以跟着文档走一遍,不习惯的话,可以跟着下文摸索

我们以官方示范课程为例:edx-demo-course,这门课在新安装的平台中都预制了,在studio中导出到本地,然后解压后即可看到如下结构

tree ./course -d(列出所有目录)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
:::text
├── about
├── annotatable
├── assets
├── chapter
├── course
├── discussion
├── drafts
│   ├── annotatable
│   ├── discussion
│   ├── html
│   ├── problem
│   ├── vertical
│   └── video
├── html
├── info
├── policies
│   └── course
├── problem
├── sequential
├── static
│   ├── VGL
│   │   ├── edx
│   │   ├── localhost
│   │   ├── mitx-lms
│   │   ├── mitx-staging
│   │   ├── original
│   │   └── sandbox
│   ├── applets
│   ├── css
│   ├── handouts
│   ├── images
│   ├── js
│   │   ├── IGV
│   │   │   ├── js
│   │   │   └── resources
│   │   ├── i18n
│   │   └── loupeAndLightbox
│   ├── jsmol
│   │   └── j2s
│   │       ├── com
│   │       │   └── jcraft
│   │       │       └── jzlib
│   │       ├── java
│   │       │   ├── awt
│   │       │   │   └── event
│   │       │   ├── io
│   │       │   ├── lang
│   │       │   │   ├── annotation
│   │       │   │   └── reflect
│   │       │   ├── net
│   │       │   ├── text
│   │       │   └── util
│   │       │       ├── regex
│   │       │       └── zip
│   │       ├── make
│   │       ├── org
│   │       │   └── jmol
│   │       │       ├── adapter
│   │       │       │   ├── readers
│   │       │       │   │   ├── cifpdb
│   │       │       │   │   ├── molxyz
│   │       │       │   │   ├── more
│   │       │       │   │   ├── quantum
│   │       │       │   │   ├── simple
│   │       │       │   │   ├── xml
│   │       │       │   │   └── xtal
│   │       │       │   └── smarter
│   │       │       ├── api
│   │       │       ├── appletjs
│   │       │       ├── atomdata
│   │       │       ├── awtjs
│   │       │       ├── awtjs2d
│   │       │       ├── bspt
│   │       │       ├── constant
│   │       │       ├── exportjs
│   │       │       ├── g3d
│   │       │       ├── geodesic
│   │       │       ├── i18n
│   │       │       ├── io
│   │       │       ├── io2
│   │       │       ├── jvxl
│   │       │       │   ├── api
│   │       │       │   ├── calc
│   │       │       │   ├── data
│   │       │       │   └── readers
│   │       │       ├── minimize
│   │       │       │   └── forcefield
│   │       │       │       └── data
│   │       │       ├── modelset
│   │       │       ├── modelsetbio
│   │       │       ├── navigate
│   │       │       ├── parallel
│   │       │       ├── quantum
│   │       │       ├── render
│   │       │       ├── renderbio
│   │       │       ├── renderspecial
│   │       │       ├── rendersurface
│   │       │       ├── script
│   │       │       ├── shape
│   │       │       ├── shapebio
│   │       │       ├── shapespecial
│   │       │       ├── shapesurface
│   │       │       ├── smiles
│   │       │       ├── symmetry
│   │       │       ├── thread
│   │       │       ├── util
│   │       │       └── viewer
│   │       │           └── binding
│   │       └── test
│   ├── molecules
│   ├── python
│   └── subs
├── tabs
├── vertical
└── video

115 directories

其中大多目录一目了然

课程meta信息

参见root目录下的course.xml文件,这就是我们在studio中创建课程时,填写的数据

关联信息

课程的结构描述信息在course/course.xml,高级配置也在其中,这个文件的命名规则由根目录下的course.xml文件的url_name字段信息确定

而course/course.xml可视为这门课程的地图

结构细节

The Structure of the Manual Testing Course

对于demo课程的细节,可以阅读这篇文档

其中可能引起的疑惑有两个

其一是资源定位的问题,如何关联到相关资源,OLX给出的策略似乎是uuid,生成规则猜测为:uuid.uuid4().get_hex()

其二是unicode(中文)编码的问题,如果你看到你的python入门.pdf在OLX文档中变为python\u5165\u95e8.pdf这是完全正常的

UUID

UUID是128位的全局唯一标识符,通常由32字节的字符串表示。它可以保证时间和空间的唯一性,也称为GUID

UUID主要有五个算法,也就是五种方法来实现:

  • uuid1()——基于时间戳。由MAC地址、当前时间戳、随机数生成。可以保证全球范围内的唯一性, 但MAC的使用同时带来安全性问题,局域网中可以使用IP来代替MAC
  • uuid2()——基于分布式计算环境DCE(Python中没有这个函数)
  • uuid3()——基于名字的MD5散列值:通过计算名字和命名空间的MD5散列值得到,保证了同一命名空间中不同名字的唯一性, 和不同命名空间的唯一性,但同一命名空间的同一名字生成相同的uuid。
  • uuid4()——基于随机数,由伪随机数得到,有一定的重复概率,该概率可以计算出来
  • uuid5()——基于名字的SHA-1散列值

若在Global的分布式计算环境下,最好用uuid1;若有名字的唯一性要求,最好用uuid3或uuid5。

参考