44namespace NLU . DevOps . Core
55{
66 using System ;
7+ using System . Collections . Generic ;
8+ using System . Diagnostics ;
79 using Newtonsoft . Json ;
810 using Newtonsoft . Json . Linq ;
911
@@ -16,42 +18,33 @@ public EntityConverter(string utterance)
1618
1719 private string Utterance { get ; }
1820
21+ private string Prefix { get ; set ; } = string . Empty ;
22+
1923 public override Entity ReadJson ( JsonReader reader , Type objectType , Entity existingValue , bool hasExistingValue , JsonSerializer serializer )
2024 {
25+ Debug . Assert ( ! hasExistingValue , "Entity instance can only be constructor initialized." ) ;
26+
2127 var jsonObject = JObject . Load ( reader ) ;
28+ return typeof ( HierarchicalEntity ) . IsAssignableFrom ( objectType )
29+ ? this . ReadHierarchicalEntity ( jsonObject , serializer )
30+ : this . ReadEntity ( jsonObject , objectType , serializer ) ;
31+ }
32+
33+ public override void WriteJson ( JsonWriter writer , Entity value , JsonSerializer serializer )
34+ {
35+ throw new NotImplementedException ( ) ;
36+ }
37+
38+ private Entity ReadEntity ( JObject jsonObject , Type objectType , JsonSerializer serializer )
39+ {
2240 var matchText = jsonObject . Value < string > ( "matchText" ) ;
41+ var matchIndex = jsonObject . Value < int > ( "matchIndex" ) ;
2342 var startPosOrNull = jsonObject . Value < int ? > ( "startPos" ) ;
2443 var endPosOrNull = jsonObject . Value < int ? > ( "endPos" ) ;
25- if ( matchText == null && startPosOrNull != null && endPosOrNull != null )
44+ if ( matchText == null && startPosOrNull . HasValue && endPosOrNull . HasValue )
2645 {
27- var startPos = startPosOrNull . Value ;
28- var endPos = endPosOrNull . Value ;
29- var length = endPos - startPos + 1 ;
30- if ( ! this . IsValid ( startPos , endPos ) )
31- {
32- throw new InvalidOperationException (
33- $ "Invalid start position '{ startPos } ' or end position '{ endPos } ' for utterance '{ this . Utterance } '.") ;
34- }
35-
36- matchText = this . Utterance . Substring ( startPos , length ) ;
46+ ( matchText , matchIndex ) = this . GetMatchInfo ( startPosOrNull . Value , endPosOrNull . Value ) ;
3747 jsonObject . Add ( "matchText" , matchText ) ;
38- var matchIndex = 0 ;
39- var currentPos = 0 ;
40- while ( true )
41- {
42- currentPos = this . Utterance . IndexOf ( matchText , currentPos , StringComparison . InvariantCulture ) ;
43-
44- // Because 'matchText' is derived from the utterance from 'startPos' and 'endPos',
45- // we are guaranteed to find a match at with index 'startPos'.
46- if ( currentPos == startPos )
47- {
48- break ;
49- }
50-
51- currentPos += length ;
52- matchIndex ++ ;
53- }
54-
5548 jsonObject . Add ( "matchIndex" , matchIndex ) ;
5649 jsonObject . Remove ( "startPos" ) ;
5750 jsonObject . Remove ( "endPos" ) ;
@@ -76,9 +69,86 @@ public override Entity ReadJson(JsonReader reader, Type objectType, Entity exist
7669 }
7770 }
7871
79- public override void WriteJson ( JsonWriter writer , Entity value , JsonSerializer serializer )
72+ private HierarchicalEntity ReadHierarchicalEntity ( JObject jsonObject , JsonSerializer serializer )
8073 {
81- throw new NotImplementedException ( ) ;
74+ var matchText = jsonObject . Value < string > ( "matchText" ) ;
75+ var matchIndex = jsonObject . Value < int > ( "matchIndex" ) ;
76+ var startPosOrNull = jsonObject . Value < int ? > ( "startPos" ) ;
77+ var endPosOrNull = jsonObject . Value < int ? > ( "endPos" ) ;
78+ if ( matchText == null && startPosOrNull . HasValue && endPosOrNull . HasValue )
79+ {
80+ ( matchText , matchIndex ) = this . GetMatchInfo ( startPosOrNull . Value , endPosOrNull . Value ) ;
81+ }
82+
83+ var entityType = jsonObject . Value < string > ( "entityType" ) ?? jsonObject . Value < string > ( "entity" ) ;
84+ var childrenJson = jsonObject [ "children" ] ;
85+ var children = default ( IEnumerable < HierarchicalEntity > ) ;
86+ if ( childrenJson != null )
87+ {
88+ var prefix = $ "{ entityType } ::";
89+ this . Prefix += prefix ;
90+ try
91+ {
92+ children = childrenJson . ToObject < IEnumerable < HierarchicalEntity > > ( serializer ) ;
93+ }
94+ finally
95+ {
96+ this . Prefix = this . Prefix . Substring ( 0 , this . Prefix . Length - prefix . Length ) ;
97+ }
98+ }
99+
100+ var entity = new HierarchicalEntity ( $ "{ this . Prefix } { entityType } ", jsonObject [ "entityValue" ] , matchText , matchIndex , children ) ;
101+ foreach ( var property in jsonObject )
102+ {
103+ switch ( property . Key )
104+ {
105+ case "children" :
106+ case "endPos" :
107+ case "entity" :
108+ case "entityType" :
109+ case "entityValue" :
110+ case "matchText" :
111+ case "matchIndex" :
112+ case "startPos" :
113+ break ;
114+ default :
115+ var value = property . Value is JValue jsonValue ? jsonValue . Value : property . Value ;
116+ entity . AdditionalProperties . Add ( property . Key , value ) ;
117+ break ;
118+ }
119+ }
120+
121+ return entity ;
122+ }
123+
124+ private Tuple < string , int > GetMatchInfo ( int startPos , int endPos )
125+ {
126+ if ( ! this . IsValid ( startPos , endPos ) )
127+ {
128+ throw new InvalidOperationException (
129+ $ "Invalid start position '{ startPos } ' or end position '{ endPos } ' for utterance '{ this . Utterance } '.") ;
130+ }
131+
132+ var length = endPos - startPos + 1 ;
133+ var matchText = this . Utterance . Substring ( startPos , length ) ;
134+ var matchIndex = 0 ;
135+ var currentPos = 0 ;
136+ while ( true )
137+ {
138+ currentPos = this . Utterance . IndexOf ( matchText , currentPos , StringComparison . InvariantCulture ) ;
139+
140+ // Because 'matchText' is derived from the utterance from 'startPos' and 'endPos',
141+ // we are guaranteed to find a match at with index 'startPos'.
142+ if ( currentPos == startPos )
143+ {
144+ break ;
145+ }
146+
147+ currentPos += length ;
148+ matchIndex ++ ;
149+ }
150+
151+ return Tuple . Create ( matchText , matchIndex ) ;
82152 }
83153
84154 private bool IsValid ( int startPos , int endPos )
0 commit comments