@@ -45,7 +45,7 @@ private static void Generate(this OpenXmlElement xmlElement, WordprocessingDocum
4545 // avoid {{tag}} like <t>{</t><t>{</t>
4646 //AvoidSplitTagText(xmlElement);
4747 // avoid {{tag}} like <t>aa{</t><t>{</t> test in...
48- AvoidSplitTagText ( xmlElement , GetReplaceKeys ( tags ) ) ;
48+ AvoidSplitTagText ( xmlElement ) ;
4949
5050 //Tables
5151 var tables = xmlElement . Descendants < Table > ( ) . ToArray ( ) ;
@@ -56,16 +56,15 @@ private static void Generate(this OpenXmlElement xmlElement, WordprocessingDocum
5656
5757 foreach ( var tr in trs )
5858 {
59-
6059 var matchs = ( Regex . Matches ( tr . InnerText , "(?<={{).*?\\ ..*?(?=}})" )
6160 . Cast < Match > ( ) . GroupBy ( x => x . Value ) . Select ( varGroup => varGroup . First ( ) . Value ) ) . ToArray ( ) ;
6261 if ( matchs . Length > 0 )
6362 {
6463 var listKeys = matchs . Select ( s => s . Split ( '.' ) [ 0 ] ) . Distinct ( ) . ToArray ( ) ;
6564 // TODO:
66- // not support > 1 list in same tr
67- if ( listKeys . Length > 1 )
68- throw new NotSupportedException ( "MiniWord doesn't support more than 1 list in same row" ) ;
65+ // not support > 2 list in same tr
66+ if ( listKeys . Length > 2 )
67+ throw new NotSupportedException ( "MiniWord doesn't support more than 2 list in same row" ) ;
6968 var listKey = listKeys [ 0 ] ;
7069 if ( tags . ContainsKey ( listKey ) && tags [ listKey ] is IEnumerable )
7170 {
@@ -82,7 +81,9 @@ private static void Generate(this OpenXmlElement xmlElement, WordprocessingDocum
8281 var dicKey = $ "{ listKey } .{ e . Key } ";
8382 dic . Add ( dicKey , e . Value ) ;
8483 }
85-
84+
85+ ReplaceStatements ( xmlElement , tags ) ;
86+
8687 ReplaceText ( newTr , docx , tags : dic ) ;
8788 table . Append ( newTr ) ;
8889 }
@@ -92,6 +93,8 @@ private static void Generate(this OpenXmlElement xmlElement, WordprocessingDocum
9293 }
9394 }
9495 }
96+
97+ ReplaceStatements ( xmlElement , tags ) ;
9598
9699 ReplaceText ( xmlElement , docx , tags ) ;
97100 }
@@ -102,6 +105,7 @@ private static void AvoidSplitTagText(OpenXmlElement xmlElement)
102105 var pool = new List < Text > ( ) ;
103106 var sb = new StringBuilder ( ) ;
104107 var needAppend = false ;
108+ var foreachIncluded = false ;
105109 foreach ( var text in texts )
106110 {
107111 var clear = false ;
@@ -118,10 +122,28 @@ private static void AvoidSplitTagText(OpenXmlElement xmlElement)
118122 // TODO: check tag exist
119123 // TODO: record tag text if without tag then system need to clear them
120124 // TODO: every {{tag}} one <t>for them</t> and add text before first text and copy first one and remove {{, tagname, }}
121-
125+
126+ if ( s . StartsWith ( "{{foreach" ) )
127+ foreachIncluded = true ;
128+
122129 if ( ! s . StartsWith ( "{{" ) )
123130 clear = true ;
124- else if ( s . Contains ( "{{" ) && s . Contains ( "}}" ) )
131+ else if ( s . Contains ( "{{" ) && s . Contains ( "}}" ) && ! foreachIncluded )
132+ {
133+ if ( sb . Length <= 1000 ) // avoid too big tag
134+ {
135+ var first = pool . First ( ) ;
136+ var newText = first . Clone ( ) as Text ;
137+ newText . Text = s ;
138+ first . Parent . InsertBefore ( newText , first ) ;
139+ foreach ( var t in pool )
140+ {
141+ t . Text = "" ;
142+ }
143+ }
144+ clear = true ;
145+ }
146+ else if ( s . Contains ( "{{foreach" ) && s . Contains ( "endforeach}}" ) && foreachIncluded )
125147 {
126148 if ( sb . Length <= 1000 ) // avoid too big tag
127149 {
@@ -135,7 +157,9 @@ private static void AvoidSplitTagText(OpenXmlElement xmlElement)
135157 }
136158 }
137159 clear = true ;
160+ foreachIncluded = false ;
138161 }
162+
139163 }
140164
141165 if ( clear )
@@ -173,7 +197,9 @@ private static List<string> GetReplaceKeys(Dictionary<string, object> tags)
173197 if ( item2 is Dictionary < string , object > dic )
174198 {
175199 foreach ( var item3 in dic . Keys )
200+ {
176201 keys . Add ( "{{" + item . Key + "." + item3 + "}}" ) ;
202+ }
177203 }
178204 break ;
179205 }
@@ -186,6 +212,129 @@ private static List<string> GetReplaceKeys(Dictionary<string, object> tags)
186212 return keys ;
187213 }
188214
215+ private static void ReplaceStatements ( OpenXmlElement xmlElement , Dictionary < string , object > tags )
216+ {
217+ var paragraphs = xmlElement . Descendants < Paragraph > ( ) . ToList ( ) ;
218+
219+ while ( paragraphs . Any ( s => s . InnerText . Contains ( "@if" ) ) )
220+ {
221+ var ifIndex = paragraphs . FindIndex ( 0 , s => s . InnerText . Contains ( "@if" ) ) ;
222+ var endIfFinalIndex = paragraphs . FindIndex ( ifIndex , s => s . InnerText . Contains ( "@endif" ) ) ;
223+
224+ var statement = paragraphs [ ifIndex ] . InnerText . Split ( ' ' ) ;
225+
226+ var checkStatement = EvaluateStatement ( tags [ statement [ 1 ] ] , statement [ 2 ] , statement [ 3 ] ) ;
227+
228+ if ( checkStatement )
229+ {
230+ for ( int i = ifIndex + 1 ; i <= endIfFinalIndex - 1 ; i ++ )
231+ {
232+ paragraphs [ i ] . Remove ( ) ;
233+ }
234+ }
235+
236+ paragraphs [ ifIndex ] . Remove ( ) ;
237+ paragraphs [ endIfFinalIndex ] . Remove ( ) ;
238+
239+ paragraphs = xmlElement . Descendants < Paragraph > ( ) . ToList ( ) ;
240+ }
241+ }
242+
243+ private static bool EvaluateStatement ( object tagValue , string comparisonOperator , string value )
244+ {
245+ var checkStatement = false ;
246+
247+ switch ( tagValue )
248+ {
249+ case double dtg when double . TryParse ( value , out var doubleNumber ) :
250+ switch ( comparisonOperator )
251+ {
252+ case "==" :
253+ checkStatement = ! dtg . Equals ( doubleNumber ) ;
254+ break ;
255+ case "!=" :
256+ checkStatement = dtg . Equals ( doubleNumber ) ;
257+ break ;
258+ case ">" :
259+ checkStatement = dtg <= doubleNumber ;
260+ break ;
261+ case "<" :
262+ checkStatement = dtg >= doubleNumber ;
263+ break ;
264+ case ">=" :
265+ checkStatement = dtg < doubleNumber ;
266+ break ;
267+ case "<=" :
268+ checkStatement = dtg > doubleNumber ;
269+ break ;
270+ }
271+
272+ break ;
273+ case int itg when int . TryParse ( value , out var intNumber ) :
274+ switch ( comparisonOperator )
275+ {
276+ case "==" :
277+ checkStatement = ! itg . Equals ( intNumber ) ;
278+ break ;
279+ case "!=" :
280+ checkStatement = itg . Equals ( intNumber ) ;
281+ break ;
282+ case ">" :
283+ checkStatement = itg <= intNumber ;
284+ break ;
285+ case "<" :
286+ checkStatement = itg >= intNumber ;
287+ break ;
288+ case ">=" :
289+ checkStatement = itg < intNumber ;
290+ break ;
291+ case "<=" :
292+ checkStatement = itg > intNumber ;
293+ break ;
294+ }
295+
296+ break ;
297+ case DateTime dttg when DateTime . TryParse ( value , out var date ) :
298+ switch ( comparisonOperator )
299+ {
300+ case "==" :
301+ checkStatement = ! dttg . Equals ( date ) ;
302+ break ;
303+ case "!=" :
304+ checkStatement = dttg . Equals ( date ) ;
305+ break ;
306+ case ">" :
307+ checkStatement = dttg <= date ;
308+ break ;
309+ case "<" :
310+ checkStatement = dttg >= date ;
311+ break ;
312+ case ">=" :
313+ checkStatement = dttg < date ;
314+ break ;
315+ case "<=" :
316+ checkStatement = dttg > date ;
317+ break ;
318+ }
319+
320+ break ;
321+ case string stg :
322+ switch ( comparisonOperator )
323+ {
324+ case "==" :
325+ checkStatement = stg != value ;
326+ break ;
327+ case "!=" :
328+ checkStatement = stg == value ;
329+ break ;
330+ }
331+
332+ break ;
333+ }
334+
335+ return checkStatement ;
336+ }
337+
189338 private static void ReplaceText ( OpenXmlElement xmlElement , WordprocessingDocument docx , Dictionary < string , object > tags )
190339 {
191340 var paragraphs = xmlElement . Descendants < Paragraph > ( ) . ToArray ( ) ;
@@ -203,6 +352,19 @@ private static void ReplaceText(OpenXmlElement xmlElement, WordprocessingDocumen
203352 foreach ( var tag in tags )
204353 {
205354 var isMatch = t . Text . Contains ( $ "{{{{{tag.Key}}}}}") ;
355+
356+ if ( ! isMatch && tag . Value is List < MiniWordForeach > forTags )
357+ {
358+ if ( forTags . Any ( forTag => forTag . Value . Keys . Any ( dictKey =>
359+ {
360+ var innerTag = "{{" + tag . Key + "." + dictKey + "}}" ;
361+ return t . Text . Contains ( innerTag ) ;
362+ } ) ) )
363+ {
364+ isMatch = true ;
365+ }
366+ }
367+
206368 if ( isMatch )
207369 {
208370 if ( tag . Value is string [ ] || tag . Value is IList < string > || tag . Value is List < string > )
@@ -223,6 +385,31 @@ private static void ReplaceText(OpenXmlElement xmlElement, WordprocessingDocumen
223385 }
224386 t . Remove ( ) ;
225387 }
388+ else if ( tag . Value is List < MiniWordForeach > vs )
389+ {
390+ var currentT = t ;
391+ var generatedText = new Text ( ) ;
392+ currentT . Text = currentT . Text . Replace ( @"{{foreach" , "" ) . Replace ( @"endforeach}}" , "" ) ;
393+ for ( var i = 0 ; i < vs . Count ; i ++ )
394+ {
395+ var newT = t . CloneNode ( true ) as Text ;
396+
397+ foreach ( var vv in vs [ i ] . Value )
398+ {
399+ newT . Text = newT . Text . Replace ( "{{" + tag . Key + "." + vv . Key + "}}" , vv . Value . ToString ( ) ) ;
400+ }
401+
402+ if ( i != vs . Count )
403+ {
404+ newT . Text += vs [ i ] . Separator ;
405+ }
406+
407+ generatedText . Text += newT . Text ;
408+ }
409+
410+ run . Append ( generatedText ) ;
411+ t . Remove ( ) ;
412+ }
226413 else if ( tag . Value is MiniWordPicture )
227414 {
228415 var pic = ( MiniWordPicture ) tag . Value ;
0 commit comments