NIMKitRobotDefaultTemplateParser.m 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. //
  2. // NIMKitRobotTemplateParser.m
  3. // NIMKit
  4. //
  5. // Created by chris on 2017/6/25.
  6. // Copyright © 2017年 NetEase. All rights reserved.
  7. //
  8. #import "NIMKitRobotDefaultTemplateParser.h"
  9. #import "NSDictionary+NIMKit.h"
  10. #import <NIMSDK/NIMSDK.h>
  11. // 三种容器类(可嵌套)标签名
  12. #define NIMKitRobotElementNameTemplate @"template"
  13. #define NIMKitRobotElementNameLayout @"LinearLayout"
  14. #define NIMKitRobotElementNameLink @"link"
  15. #define NNIMKitRobotResponseTypeText @"01" //文本消息,
  16. #define NNIMKitRobotResponseTypeImage @"02" //图片消息,
  17. #define NNIMKitRobotResponseTypeFast @"03" //快速回复
  18. #define NNIMKitRobotResponseTypeComplex @"11" //复杂模板
  19. @interface NIMKitRobotDefaultTemplateParser()<NSXMLParserDelegate>
  20. {
  21. NSString *_currentTagName;
  22. NSString *_currentMessageId;
  23. //可以成为容器类的 Class ,即实现了 NIMKitRobotTemplateContainer 协议
  24. NSSet *_containerClass;
  25. //容器,用来区分 tag 间的层级关系
  26. NSMutableArray *_containers;
  27. }
  28. @property (nonatomic,strong) NSMutableDictionary *robotTemplates;
  29. @property (nonatomic,strong) NSDictionary<NSString *, NSNumber *> *elementNameMapping;
  30. @end
  31. @implementation NIMKitRobotDefaultTemplateParser
  32. - (instancetype)init
  33. {
  34. self = [super init];
  35. if (self)
  36. {
  37. _elementNameMapping = @{
  38. //属性特殊字段映射
  39. @"text" : @(NIMKitRobotTemplateItemTypeText),
  40. @"image" : @(NIMKitRobotTemplateItemTypeImage),
  41. @"link" : @(NIMKitRobotTemplateItemTypeLink),
  42. };
  43. _containerClass = [NSSet setWithObjects:@"NIMKitRobotTemplate",@"NIMKitRobotTemplateLayout",@"NIMKitRobotTemplateLinkItem",nil];
  44. _containers = [[NSMutableArray alloc] init];
  45. _robotTemplates = [[NSMutableDictionary alloc] init];
  46. }
  47. return self;
  48. }
  49. - (void)clean
  50. {
  51. [self.robotTemplates removeAllObjects];
  52. }
  53. - (NIMKitRobotTemplate *)robotTemplate:(NIMMessage *)message
  54. {
  55. NIMKitRobotTemplate *template = [self.robotTemplates objectForKey:message.messageId];
  56. if (template)
  57. {
  58. return template;
  59. }
  60. _currentMessageId = message.messageId;
  61. NIMRobotObject *object = (NIMRobotObject *)message.messageObject;
  62. NSString *flag = [object.response nimkit_jsonString:@"flag"];
  63. if ([flag isEqualToString:@"bot"])
  64. {
  65. return [self resolveBotTemplate:object];
  66. }
  67. if ([flag isEqualToString:@"faq"])
  68. {
  69. return [self resolveFaqTemplate:object];
  70. }
  71. NSAssert(0, @"invalid robot template");
  72. return nil;
  73. }
  74. - (NIMKitRobotTemplate *)resolveBotTemplate:(NIMRobotObject *)object
  75. {
  76. NIMKitRobotTemplate *template = [[NIMKitRobotTemplate alloc] init];
  77. template.version = @"0.1"; //默认版本
  78. [self.robotTemplates setObject:template forKey:object.message.messageId];
  79. for (NSDictionary *dict in [object.response nimkit_jsonArray:@"message"])
  80. {
  81. if ([dict isKindOfClass:[NSDictionary class]])
  82. {
  83. NSString *templateText = [dict nimkit_jsonString:@"content"];
  84. NSString *type = [dict nimkit_jsonString:@"type"];
  85. if([type isEqualToString:NNIMKitRobotResponseTypeComplex] )
  86. {
  87. [self parse:templateText];
  88. }
  89. if ([type isEqualToString:NNIMKitRobotResponseTypeText])
  90. {
  91. NIMKitRobotTemplateLayout *layout = [self genTextRobotLayout:templateText];
  92. [template.items addObject:layout];
  93. }
  94. if ([type isEqualToString:NNIMKitRobotResponseTypeImage])
  95. {
  96. NIMKitRobotTemplateLayout *layout = [self genImageRobotLayout:templateText];
  97. [template.items addObject:layout];
  98. }
  99. }
  100. }
  101. return template;
  102. }
  103. - (NIMKitRobotTemplate *)resolveFaqTemplate:(NIMRobotObject *)object
  104. {
  105. NIMKitRobotTemplate *template = [[NIMKitRobotTemplate alloc] init];
  106. template.version = @"0.1"; //默认版本
  107. NSDictionary *match = [[object.response nimkit_jsonDict:@"message"] nimkit_jsonArray:@"match"].firstObject;
  108. if ([match isKindOfClass:[NSDictionary class]])
  109. {
  110. NSString *answer = [match nimkit_jsonString:@"answer"];
  111. NIMKitRobotTemplateLayout *layout = [self genTextRobotLayout:answer];
  112. [template.items addObject:layout];
  113. }
  114. return template;
  115. }
  116. - (BOOL)parse:(NSString *)templateText
  117. {
  118. NSData *data = [templateText dataUsingEncoding:NSUTF8StringEncoding];
  119. NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
  120. parser.delegate = self;
  121. return [parser parse];
  122. }
  123. - (NIMKitRobotTemplateLayout *)genTextRobotLayout:(NSString *)templateText
  124. {
  125. NIMKitRobotTemplateLayout *layout = [[NIMKitRobotTemplateLayout alloc] init];
  126. NIMKitRobotTemplateItem *templateItem = [[NIMKitRobotTemplateItem alloc] init];
  127. templateItem.content = templateText;
  128. templateItem.itemType = NIMKitRobotTemplateItemTypeText;
  129. layout.items = [@[templateItem] mutableCopy];
  130. return layout;
  131. }
  132. - (NIMKitRobotTemplateLayout *)genImageRobotLayout:(NSString *)templateText
  133. {
  134. NIMKitRobotTemplateLayout *layout = [[NIMKitRobotTemplateLayout alloc] init];
  135. NIMKitRobotTemplateItem *templateItem = [[NIMKitRobotTemplateItem alloc] init];
  136. templateItem.url = templateText;
  137. templateItem.itemType = NIMKitRobotTemplateItemTypeImage;
  138. CGFloat defaultImageWidth = 75.f;
  139. CGFloat defaultImageHeight = 75.f;
  140. templateItem.width = @(defaultImageWidth).stringValue;
  141. templateItem.height = @(defaultImageHeight).stringValue;
  142. layout.items = [@[templateItem] mutableCopy];
  143. return layout;
  144. }
  145. #pragma mark - NSXMLParserDelegate
  146. - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
  147. {
  148. //由于系统XML解析器是一级一级解下去的,所以要记录好当前容器,用来表示嵌套关系
  149. //当遇到容器类时,总容器 _containers 会加上这个容器类的 items , 下一次解析即使用这个 items 容器
  150. //当解析节点结束时,如果节点为容器节点,则在总容器里 _containers 里去掉最后一个容器,下一次解析会自动用上一层的容器,符合 xml 的嵌套关系
  151. _currentTagName = elementName;
  152. NSObject *item = nil;
  153. if ([elementName isEqualToString:NIMKitRobotElementNameTemplate])
  154. {
  155. NIMKitRobotTemplate *robotTemplate = [self.robotTemplates objectForKey:_currentMessageId];
  156. item = robotTemplate;
  157. }
  158. else if ([elementName isEqualToString:NIMKitRobotElementNameLayout])
  159. {
  160. NIMKitRobotTemplateLayout *layout = [[NIMKitRobotTemplateLayout alloc] init];
  161. [_containers.lastObject addObject:layout];
  162. item = layout;
  163. }
  164. else
  165. {
  166. NIMKitRobotTemplateItem *templateItem;
  167. if ([elementName isEqualToString:NIMKitRobotElementNameLink])
  168. {
  169. templateItem = [[NIMKitRobotTemplateLinkItem alloc] init];
  170. }
  171. else
  172. {
  173. templateItem = [[NIMKitRobotTemplateItem alloc] init];
  174. }
  175. [_containers.lastObject addObject:templateItem];
  176. item = templateItem;
  177. templateItem.itemType = [self.elementNameMapping nimkit_jsonInteger:elementName];
  178. }
  179. if ([_containerClass containsObject:NSStringFromClass([item class])]) {
  180. id<NIMKitRobotTemplateContainer> container = (id<NIMKitRobotTemplateContainer>)item;
  181. [_containers addObject:container.items];
  182. }
  183. for (NSString *key in attributeDict)
  184. {
  185. id value = [attributeDict objectForKey:key];
  186. [item setValue:value forKey:key];
  187. }
  188. }
  189. - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
  190. _currentTagName = nil;
  191. if ([elementName isEqualToString:NIMKitRobotElementNameTemplate]
  192. || [elementName isEqualToString:NIMKitRobotElementNameLayout]
  193. || [elementName isEqualToString:NIMKitRobotElementNameLink])
  194. {
  195. [_containers removeLastObject];
  196. }
  197. }
  198. - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
  199. string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  200. if ([string isEqualToString:@""]) {
  201. return;
  202. }
  203. NIMKitRobotTemplateItem *templateItem = [(NSArray *)_containers.lastObject lastObject];
  204. if ([_currentTagName isEqualToString:@"text"] && templateItem) {
  205. //文本过长会分段解析,这里要追加
  206. NSString *content = templateItem.content? templateItem.content : @"";
  207. templateItem.content = [content stringByAppendingString:string];;
  208. }
  209. }
  210. - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
  211. {
  212. NSLog(@"parser error: %@",parseError);
  213. }
  214. - (void)parser:(NSXMLParser *)parser validationErrorOccurred:(NSError *)validationError
  215. {
  216. NSLog(@"validation error: %@",validationError);
  217. }
  218. @end