Open DigitalPlatform opened 2 years ago
0.02 版机构代码的映射算法针对 0.01 版做了改进。改进的目的是支持同一个馆代码的读者记录,可以按照一定特征定义多种机构代码,这样和册记录的能力拉齐了。
改进之处,主要是 1) ownerInstitution 增加了一个属性 version,如果这个属性缺省,表示 0.01 版;如果属性值为 "0.02",表示 0.02 版。 2) item 元素的 map 属性值,在 0.02 版中不再默认前方一致匹配的效果,而是精确一致的效果。要实现前方一致的匹配效果,应在模式字符串最后加上一个星号。 3) 对读者记录匹配的算法进行了改进,从 0.01 版的直接利用 馆代码+"/" 作为实例字符串进行匹配,改为利用读者记录中 department 和 readerType 元素内容构造出实例字符串进行匹配。 4) 给 ownerInstitution/item 元素增加了 type 属性定义
定义举例如下:
<rfid>
<ownerInstitution version="0.02">
<item map="星洲小学/*" isil="CN-0000001-XZ" />
<item map="/*" isil="CN-0000001-ZG" />
<item map="海淀分馆/*" isil="CN-0000001-HD" />
<item map="西城分馆/*" isil="CN-0000001-XC" />
</ownerInstitution>
</rfid>
册记录的机构代码是根据其 location 元素内容映射得到的。获取实例字符串的方法和 0.01 版一致。即:将 location 元素内容依次和每个 ownerInstitution/item 元素进行匹配。不过需要注意的是,item 元素的 map 属性值,也就是模式字符串,是默认精确一致的,这一点和 0.01 算法不同。
从读者记录中抽取的实例字符串,是根据其从属馆代码+department 元素内容、馆代码+readerType 元素一共两种内容映射得到的。
这两种内容的产生规则是: 1) 馆代码+department元素内容:假设馆代码为”海淀分馆“,department 元素内容为”2019级1班“,那么产生一个字符串内容是”海淀分馆/2019级1班“ 2) 馆代码+readerType元素内容:假设馆代码为”海淀分馆“,readerType 元素内容为”普通读者“,那么产生一个字符串内容是”海淀分馆/readerType:普通读者“。注意大小写敏感,T 是大写字母
匹配算法是:
将上述两种内容,分两轮,依次和每个 ownerInstitution/item 元素进行匹配。如果任何一轮命中,则取出命中 item 元素的 isil 或 alternative 属性值,即得到机构代码,不再进行后面的匹配。
匹配过程中,针对每个 item 元素,首先检查 type 属性是否和当前”读者记录类型“匹配。type 属性缺省情况,其值为 "entity,patron",其中 "patron" 即指册记录类型。也就是说 type 属性为 "patron" 或 ”entity,patron“ 都是匹配的,而 "entity" 或 "" 都是不匹配的。(type 属性值里面是逗号分隔的值列表,一个一个的值,是不会用通配符的。)
然后继续针对 item 元素的 map 属性进行匹配,用准备好的实例字符串内容进行匹配。注意,map 属性值,0.02 版默认精确一致算法。即,不再像 0.01 版那样自动为模式字符串最后加一个星号进行匹配。
注:每一轮匹配过程中,如果有多个 item 元素命中,则取 map 属性最长的一个 item 当作最后命中结果。
dp2SSL.ShelfData.GetOwerInstitution() 函数:
// parameters:
// cfg_dom 根元素是 rfid
// strLocation 纯净的 location 元素内容。
// isil [out] 返回 ISIL 形态的代码
// alternative [out] 返回其他形态的代码
// return:
// true 找到。信息在 isil 和 alternative 参数里面返回
// false 没有找到
public static bool GetOwnerInstitution(
string strLocation,
out string isil,
out string alternative)
dp2SSL.EntityReplication.GetInstitution() 函数:
public static string GetInstitution(string location)
dp2SSL.EntityReplication.DownloadAllEntityRecordAsync() 函数:
public static async Task<NormalResult> DownloadAllEntityRecordAsync(
List<string> item_dbnames,
List<string> unprocessed_dbnames,
Delegate_writeLog writeLog,
CancellationToken token)
用于 dp2ssl 首次自动下载全部册记录到本地缓存。配置页面的菜单“重做全量同步册记录和书目摘要”可以随时促使 dp2ssl 重做一次自动下载。
dp2SSL.EntityReplication.GetUII() 函数:
static string GetUii(string strRecord)
用于同步操作日志中的 setEntity 类型(action='new')动作时,获得 UII 以便兑现刷新本地库中缓存的册记录
dp2SSL.EntityReplication.UpdateLocalEntityRecordAsync() 函数:
static async Task<NormalResult> UpdateLocalEntityRecordAsync(
string strRecPath,
string strRecord)
用于同步操作日志中的 setEntity 类型(action='new' 'change' 'transfer')动作时,兑现刷新本地库中缓存的册记录
dp2SSL.EntityReplication.DeleteLocalEntityRecord() 函数:
static NormalResult DeleteLocalEntityRecord(
string strRecPath,
string strRecord)
用于同步操作日志中的 setEntity 类型(action='delete')动作时,兑现删除本地库中缓存的册记录
GetOwnerInstitution(string, System.Xml.XmlDocument, out string, out string) (dp2SSL.ShelfData)
--GetPatronOiPii(System.Xml.XmlDocument) (dp2SSL.LibraryChannelUtil)
----DeleteLocalPatronRecord(string) (dp2SSL.LibraryChannelUtil)
------TraceSetReaderInfo(System.Xml.XmlDocument, dp2SSL.Models.PatronReplication.ProcessInfo) (dp2SSL.Models.PatronReplication)
--------DoReplication(string, string, DigitalPlatform.LibraryClient.LogType, System.Threading.CancellationToken) (dp2SSL.Models.PatronReplication)
----------StartMonitorTask() (dp2SSL.ShelfData)
------------PrepareShelfAsync() (dp2SSL.App)
--------------PageShelf_Loaded(object, System.Windows.RoutedEventArgs) (dp2SSL.PageShelf)
----UpdateLocalPatronRecord(dp2SSL.LibraryChannelUtil.GetReaderInfoResult, System.DateTime) (dp2SSL.LibraryChannelUtil)
------TraceBorrowOrReturn(DigitalPlatform.LibraryClient.OperLogItem, System.Xml.XmlDocument, dp2SSL.Models.PatronReplication.ProcessInfo) (dp2SSL.Models.PatronReplication)
--------DoReplication(string, string, DigitalPlatform.LibraryClient.LogType, System.Threading.CancellationToken) (dp2SSL.Models.PatronReplication)
----------StartMonitorTask() (dp2SSL.ShelfData)
------------PrepareShelfAsync() (dp2SSL.App)
--------------PageShelf_Loaded(object, System.Windows.RoutedEventArgs) (dp2SSL.PageShelf)
------TraceSetReaderInfo(System.Xml.XmlDocument, dp2SSL.Models.PatronReplication.ProcessInfo) (dp2SSL.Models.PatronReplication)
--------DoReplication(string, string, DigitalPlatform.LibraryClient.LogType, System.Threading.CancellationToken) (dp2SSL.Models.PatronReplication)
----------StartMonitorTask() (dp2SSL.ShelfData)
------------PrepareShelfAsync() (dp2SSL.App)
--------------PageShelf_Loaded(object, System.Windows.RoutedEventArgs) (dp2SSL.PageShelf)
------FillPatronDetailAsync(dp2SSL.PageShelf.Delegate_welcome, bool) (dp2SSL.PageShelf)
--------App_LineFeed(object, dp2SSL.LineFeedEventArgs) (dp2SSL.PageShelf)
----------PageShelf_Loaded(object, System.Windows.RoutedEventArgs) (dp2SSL.PageShelf)
----------PageShelf_Unloaded(object, System.Windows.RoutedEventArgs) (dp2SSL.PageShelf)
--------FingerprintManager_Touched(object, DigitalPlatform.IO.TouchedEventArgs) (dp2SSL.PageShelf)
----------PageShelf_Loaded(object, System.Windows.RoutedEventArgs) (dp2SSL.PageShelf)
----------PageShelf_Unloaded(object, System.Windows.RoutedEventArgs) (dp2SSL.PageShelf)
--------PatronControl_InputFace(object, System.EventArgs) (dp2SSL.PageShelf)
----------PageShelf() (dp2SSL.PageShelf)
--------RefreshPatronsAsync(System.Collections.Generic.List<DigitalPlatform.RFID.TagAndData>) (dp2SSL.PageShelf)
----------App_PatronTagChanged(object, dp2SSL.NewTagChangedEventArgs) (dp2SSL.PageShelf)
------------PageShelf_Loaded(object, System.Windows.RoutedEventArgs) (dp2SSL.PageShelf)
------------PageShelf_Unloaded(object, System.Windows.RoutedEventArgs) (dp2SSL.PageShelf)
--Set(dp2SSL.PatronItem, DigitalPlatform.LibraryClient.localhost.Record, System.DateTime) (dp2SSL.Models.PatronReplication)
----DownloadAllPatronRecordAsync(dp2SSL.Models.PatronReplication.Delegate_writeLog, System.Threading.CancellationToken) (dp2SSL.Models.PatronReplication)
------StartMonitorTask() (dp2SSL.ShelfData)
--------PrepareShelfAsync() (dp2SSL.App)
----------PageShelf_Loaded(object, System.Windows.RoutedEventArgs) (dp2SSL.PageShelf)
DigitalPlatform.LibraryServer.Common/LibraryServerUtil.cs
#region 读者记录 OI
// 2022/3/5
// return:
// true 找到。信息在 isil 和 alternative 参数里面返回
// false 没有找到
// exception:
// 可能会抛出异常 Exception
public static bool GetOwnerInstitution(
XmlElement rfid,
string libraryCode,
XmlDocument readerdom,
out string isil,
out string alternative
dp2SSL/Models/shelfData.cs
// 专用于读者记录
public static bool GetOwnerInstitution(
string libraryCode,
XmlDocument readerdom,
out string isil,
out string alternative)
dp2SSL/LibraryChannelUtil.cs
// 获得读者的 PII。注意包含了 OI 部分
static string GetPatronOiPii(XmlDocument dom)
dp2SSL/LibraryChannelUtil.cs
// 把读者记录保存(更新)到本地数据库
// parameters:
// lastWriteTime 最后写入时间。采用服务器时间
// result.Value
// -1 出错
// 0 没有发生修改
// 1 发生了创建或者修改
public static NormalResult UpdateLocalPatronRecord(
GetReaderInfoResult get_result,
DateTime lastWriteTime)
\dp2SSL\Models\PatronReplication.cs
static async Task<NormalResult> TraceBorrowOrReturn(
OperLogItem item,
XmlDocument domLog,
ProcessInfo info)
\dp2SSL\Models\PatronReplication.cs
static NormalResult TraceSetReaderInfo(
XmlDocument domLog,
ProcessInfo info)
\dp2SSL\Page\PageShelf.xaml.cs
// 填充读者信息的其他字段(第二阶段)
// resut.Value
// -1 出错
// 0 没有填充
// 1 成功填充
async Task<NormalResult> FillPatronDetailAsync(
Delegate_welcome func_welcome,
bool force = false)
C:\0-ryh\code\dp2\dp2SSL\LibraryChannelUtil.cs
public static NormalResult DeleteLocalPatronRecord(string strXml)
C:\0-ryh\code\dp2\dp2SSL\Models\PatronReplication.cs
static NormalResult TraceSetReaderInfo(
XmlDocument domLog,
ProcessInfo info)
\dp2SSL\Models\PatronReplication.cs
// 设置 PatronItem 对象成员
// result.Value:
// -1 出错
// 0 需要跳过这条读者记录
// 1 成功
static SetResult Set(PatronItem patron,
Record record,
DateTime lastWriteTime)
C:\0-ryh\code\dp2\dp2SSL\Models\PatronReplication.cs
// 第一阶段:获得全部读者库记录,进入本地数据库
// result.Value
// -1 出错
// >=0 实际获得的读者记录条数
public static async Task<ReplicationPlan> DownloadAllPatronRecordAsync(
Delegate_writeLog writeLog,
CancellationToken token)
C:\0-ryh\code\dp2\dp2SSL\Models\ShelfData_monitor.cs
// 启动一般监控任务
public static void StartMonitorTask()
C:\0-ryh\code\dp2\dp2SSL\App.xaml.cs
// 为智能书柜执行一些初始化操作
public static async Task<NormalResult> PrepareShelfAsync()
C:\0-ryh\code\dp2\dp2SSL\Page\PageShelf.xaml.cs
private async void PageShelf_Loaded(object sender, RoutedEventArgs e)
#pragma warning restore VSTHRD100 // 避免使用 Async Void 方法
GetOwnerInstitution(System.Xml.XmlElement, string, string, out string, out string) (DigitalPlatform.LibraryServer.LibraryServerUtil)
GetOwnerInstitution(string, out string, out string) (dp2SSL.ShelfData)
--无下级引用DownloadTagsInfo(System.Collections.Generic.List<string>, int, dp2SSL.LibraryChannelUtil.delegate_showText, System.Threading.CancellationToken) (dp2SSL.LibraryChannelUtil)
--GetInstitution(string) (dp2SSL.Models.EntityReplication)
----DownloadUidTable(System.Collections.Generic.List<string>, System.Collections.Hashtable, dp2SSL.InventoryData.delegate_showText, System.Threading.CancellationToken) (dp2SSL.InventoryData)
------beginInventory_Click(object, System.Windows.RoutedEventArgs) (dp2SSL.PageInventory)
--------System.Windows.Markup.IComponentConnector.Connect(int, object) (dp2SSL.PageInventory)
----DeleteLocalEntityRecord(string, string) (dp2SSL.Models.EntityReplication)
------TraceSetEntity(System.Xml.XmlDocument, dp2SSL.Models.PatronReplication.ProcessInfo) (dp2SSL.Models.EntityReplication)
--------DoReplication(string, string, DigitalPlatform.LibraryClient.LogType, System.Threading.CancellationToken) (dp2SSL.Models.PatronReplication)
----------StartMonitorTask() (dp2SSL.ShelfData)
------------PrepareShelfAsync() (dp2SSL.App)
--------------PageShelf_Loaded(object, System.Windows.RoutedEventArgs) (dp2SSL.PageShelf)
----DownloadAllEntityRecordAsync(System.Collections.Generic.List<string>, System.Collections.Generic.List<string>, dp2SSL.Models.EntityReplication.Delegate_writeLog, System.Threading.CancellationToken) (dp2SSL.Models.EntityReplication)
------StartMonitorTask() (dp2SSL.ShelfData)
--------PrepareShelfAsync() (dp2SSL.App)
----------PageShelf_Loaded(object, System.Windows.RoutedEventArgs) (dp2SSL.PageShelf)
----GetUii(string) (dp2SSL.Models.EntityReplication)
------TraceSetEntity(System.Xml.XmlDocument, dp2SSL.Models.PatronReplication.ProcessInfo) (dp2SSL.Models.EntityReplication)
--------DoReplication(string, string, DigitalPlatform.LibraryClient.LogType, System.Threading.CancellationToken) (dp2SSL.Models.PatronReplication)
----------StartMonitorTask() (dp2SSL.ShelfData)
------------PrepareShelfAsync() (dp2SSL.App)
--------------PageShelf_Loaded(object, System.Windows.RoutedEventArgs) (dp2SSL.PageShelf)
----UpdateLocalEntityRecordAsync(string, string) (dp2SSL.Models.EntityReplication)
------TraceSetEntity(System.Xml.XmlDocument, dp2SSL.Models.PatronReplication.ProcessInfo) (dp2SSL.Models.EntityReplication)
--------DoReplication(string, string, DigitalPlatform.LibraryClient.LogType, System.Threading.CancellationToken) (dp2SSL.Models.PatronReplication)
----------StartMonitorTask() (dp2SSL.ShelfData)
------------PrepareShelfAsync() (dp2SSL.App)
--------------PageShelf_Loaded(object, System.Windows.RoutedEventArgs) (dp2SSL.PageShelf)
GetOwnerInstitution(System.Xml.XmlElement, string, string, out string, out string) (DigitalPlatform.LibraryServer.LibraryServerUtil)
GetOwnerInstitution(string, out string, out string) (dp2Inventory.LibraryChannelUtil)
--DownloadUidTable(System.Collections.Generic.List<string>, System.Collections.Hashtable, dp2Inventory.LibraryChannelUtil.delegate_showText, System.Threading.CancellationToken) (dp2Inventory.LibraryChannelUtil)
----toolStripButton_begin_Click(object, System.EventArgs) (dp2Inventory.InventoryDialog)
------InitializeComponent() (dp2Inventory.InventoryDialog)
-------InventoryDialog() (dp2Inventory.InventoryDialog)
0.01 版机构代码映射算法
dp2library 模块的 library.xml 文件中,rfid 元素负责配置册记录和读者记录如何映射到 OI (机构代码)。
dp2 系统内的册记录和读者记录中,并不直接存储机构代码,而是通过定义一套映射规则,将册记录和读者记录中的馆代码或者某些字段映射到机构代码。映射关系在 dp2library 模块的 library.xml 文件的 rfid/ownerInstitution 元素中配置定义。当 rfid/ownerInstitution 元素定义修改后,即便系统中的册记录和读者记录本身没有任何变化,这些记录所对应的机构代码也会发生变化,这一点要引起注意。
定义举例如下:
(注:最新版也提供了一种改进后的匹配算法,以 ownerInstitution/@version 属性值为 "0.02" 表示新版本算法。若 ownerInstitution/@version 属性缺省、或者属性值为 "0.01",则表示这是 0.01 旧版算法。本节介绍的是旧版算法)
模式匹配、实例字符串、模式字符串
映射算法采用了模式匹配技术。模式匹配是把类似 "星洲小学/西区*"这样的模式字符串,和类似 "星洲小学/西区阅览室" 这样的实例字符串进行匹配,其中模式字符串中允许使用星号、问号来表示模糊匹配的效果。但注意实例字符串中不允许使用星号和问号。
如何确定一个册记录的机构代码
要从册记录中抽取实例字符串,用于匹配。实例字符串直接采用册记录的 location 元素内容。
匹配原理: 将实例字符串,依次和每个 ownerInstitution/item 元素进行匹配。如果命中,则取出命中 item 元素的 isil 或 alternative 属性值,即得到机构代码。
匹配过程中,针对每个 item 元素,首先检查 type 属性是否和当前”册记录类型“匹配。type 属性缺省情况,其值为 "entity,patron",其中 "entity" 即指册记录类型。也就是说 type 属性为 "entity" 或 ”entity,patron“ 都是匹配的,而 "patron" 或 "" 都是不匹配的。(type 属性值里面是逗号分隔的值列表,一个一个的值,是不会用通配符的。)
然后继续针对 item 元素的 map 属性进行匹配,用册记录 location 元素内容(实例字符串)和 map 属性值里面定义的“模式字符串”进行模式匹配。注意,map 属性值,为了书写方便,”星洲小学/“ 实际上要理解为 "星洲小学/*",即,默认为末尾加了一个星号,以便实现前方一致匹配的效果。如果不希望进行前方一致的匹配(也就是说希望精确一致),可以这样定义 map 属性值”星洲小学/$“,即在末尾加上一个符号
$
表示阻止系统自动加星号。map 属性值中的模式字符串可以使用问号和星号,表示通配一个字符和任意多个字符。
注:匹配过程中,如果有多个 item 元素命中,则取 map 属性最长的一个 item 当作最后命中结果。
如何确定一个读者记录的机构代码
读者记录是用其从属馆代码+"/"构成实例字符串。(注: 0.01 版算法并不使用读者记录中的字段来构造实例字符串,这一点和 0.02 版不同)
匹配原理:
将实例字符串和每个 ownerInstitution/item 元素进行匹配。如果任何一轮命中,则取出命中 item 元素的 isil 或 alternative 属性值,即得到机构代码,不再进行后面的匹配。
匹配过程中,针对每个 item 元素,首先检查 type 属性是否和当前”读者记录类型“匹配。type 属性缺省情况,其值为 "entity,patron",其中 "patron" 即指册记录类型。也就是说 type 属性为 "patron" 或 ”entity,patron“ 都是匹配的,而 "entity" 或 "" 都是不匹配的。(type 属性值里面是逗号分隔的值列表,一个一个的值,是不会用通配符的。)
然后继续针对 item 元素的 map 属性(模式字符串)和实例字符串进行匹配。注意,map 属性值,为了书写方便,”星洲小学/“ 实际上要理解为 "星洲小学/*",即,默认为末尾加了一个星号,以便实现前方一致匹配的效果。如果不希望进行前方一致的匹配(也就是说希望精确一致),可以这样定义 map 属性值”星洲小学/$“,即在末尾加上一个符号
$
表示阻止系统自动加星号。注:每一轮匹配过程中,如果有多个 item 元素命中,则取 map 属性最长的一个 item 当作最后命中结果。
0.01 版匹配算法的缺点
0.01 版匹配算法,无法对同一个馆代码的读者记录,区分定义出两种或者以上的机构代码。而对同一个馆代码的册记录是可以做到定义多种机构代码的。
这是因为算法在对读者记录抽取实例字符串的时候,只能使用馆代码作为实例字符串;而对册记录抽取实例字符串的时候,是使用的馆藏地字段内容,馆藏地地字段内容一般为“馆代码/阅览室名”这样的形态,信息比读者记录抽取的字符串丰富得多,可以利用阅览室名部分的局部,根据模式匹配来区分映射。
为了克服这个缺点,后来增加了 0.02 版算法