2011-03-31 26 views
0

使用asp.net 4用於Word合併的字符串替換

我們在工作中進行了大量的Word合併。而不是使用Word的複雜條件語句,我想嵌入自己的語法。是這樣的:

Dear Mr. { select lastname from users where userid = 7 }, 
Your invoice for this quarter is: ${ select amount from invoices where userid = 7 }. 
...... 

理想情況下,我想這都被轉換爲:

string.Format("Dear Mr. {0}, Your invoice for this quarter is: ${1}", sqlEval[0], sqlEval[1]); 

什麼想法?

+1

什麼是更大的圖片/上下文?你真的想在查詢中包含實際的ID號嗎? – 2011-03-31 15:57:59

+0

'string.Format()'的全部意義在於,您將數據與其用於的字符串表示分開 - 您爲什麼要將它們重新合併到一起? – BrokenGlass 2011-03-31 15:58:18

+0

不知道如何生成要合併的Word文檔(即誰有權訪問它們),我不得不說這似乎是危險的,允許任意SQL被評估或exec'd像那樣.. SQL注入潛伏在那些彎曲的大括號.. – 2011-03-31 16:00:33

回答

0

我最終滾動我自己的解決方案,但謝謝。我真的不喜歡,如果發言。我需要重構它們。這裏是:

var mailingMergeString = new MailingMergeString(input); 
var output = mailingMergeString.ParseMailingMergeString(); 

public class MailingMergeString 
{ 
    private string _input; 

    public MailingMergeString(string input) 
    { 
     _input = input; 
    } 

    public string ParseMailingMergeString() 
    { 
     IList<SqlReplaceCommand> sqlCommands = new List<SqlReplaceCommand>(); 
     var i = 0; 
     const string openBrace = "{"; 
     const string closeBrace = "}"; 

     while (string.IsNullOrWhiteSpace(_input) == false) 
     { 
      var sqlReplaceCommand = new SqlReplaceCommand(); 
      var open = _input.IndexOf(openBrace) + 1; 
      var close = _input.IndexOf(closeBrace); 
      var length = close != -1 ? close - open : _input.Length; 
      var newInput = _input.Substring(close + 1); 
      var nextClose = newInput.Contains(openBrace) ? newInput.IndexOf(openBrace) : newInput.Length; 

      if (i == 0 && open > 0) 
      { 
       sqlReplaceCommand.Text = _input.Substring(0, open - 1); 
       _input = _input.Substring(open - 1); 
      } 
      else 
      { 
       sqlReplaceCommand.Command = _input.Substring(open, length); 
       sqlReplaceCommand.PlaceHolder = openBrace + i + closeBrace; 
       sqlReplaceCommand.Text = _input.Substring(close + 1, nextClose); 
       sqlReplaceCommand.NewInput = _input.Substring(close + 1); 

       _input = newInput.Contains(openBrace) ? sqlReplaceCommand.NewInput : string.Empty; 
      } 

      sqlCommands.Add(sqlReplaceCommand); 
      i++; 
     } 

     return sqlCommands.GetParsedString(); 
    } 

    internal class SqlReplaceCommand 
    { 
     public string Command { get; set; } 

     public string SqlResult { get; set; } 

     public string PlaceHolder { get; set; } 

     public string Text { get; set; } 

     protected internal string NewInput { get; set; } 
    } 
} 

internal static class SqlReplaceExtensions 
{ 
    public static string GetParsedString(this IEnumerable<MailingMergeString.SqlReplaceCommand> sqlCommands) 
    { 
     return sqlCommands.Aggregate("", (current, replaceCommand) => current + (replaceCommand.PlaceHolder + replaceCommand.Text)); 
    } 
} 
0

嗯,我真的不建議爲此滾動自己的解決方案,但是我會按照問題回答問題。

首先,您需要處理文本並提取SQL語句。爲此,您需要一個簡單的解析器:

/// <summary>Parses the input string and extracts a unique list of all placeholders.</summary> 
/// <remarks> 
/// This method does not handle escaping of delimiters 
/// </remarks> 
public static IList<string> Parse(string input) 
{ 
    const char placeholderDelimStart = '{'; 
    const char placeholderDelimEnd = '}'; 

    var characters = input.ToCharArray(); 
    var placeHolders = new List<string>(); 
    string currentPlaceHolder = string.Empty; 
    bool inPlaceHolder = false; 
    for (int i = 0; i < characters.Length; i++) 
    { 
     var currentChar = characters[i]; 

     // Start of a placeholder 
     if (!inPlaceHolder && currentChar == placeholderDelimStart) 
     { 
      currentPlaceHolder = string.Empty; 
      inPlaceHolder = true; 
      continue; 
     } 

     // Start of a placeholder when we already have one 
     if (inPlaceHolder && currentChar == placeholderDelimStart) 
      throw new InvalidOperationException("Unexpected character detected at position " + i); 

     // We found the end marker while in a placeholder - we're done with this placeholder 
     if (inPlaceHolder && currentChar == placeholderDelimEnd) 
     { 
      if (!placeHolders.Contains(currentPlaceHolder)) 
       placeHolders.Add(currentPlaceHolder); 
      inPlaceHolder = false; 
      continue; 
     } 

     // End of a placeholder with no matching start 
     if (!inPlaceHolder && currentChar == placeholderDelimEnd) 
      throw new InvalidOperationException("Unexpected character detected at position " + i); 

     if (inPlaceHolder) 
      currentPlaceHolder += currentChar; 
    } 
    return placeHolders; 
} 

好的,這樣就會得到一個從輸入文本中提取的SQL語句列表。你可能會想調整它以正確使用類型化的解析器異常和一些輸入守衛(爲了清楚起見,我忽略了它)。

現在你只需要與評估SQL的結果,以取代那些佔位符:

// Sample input 
var input = "Hello Mr. {select firstname from users where userid=7}"; 

string output = input; 
var extractedStatements = Parse(input); 
foreach (var statement in extractedStatements) 
{ 
    // Execute the SQL statement 
    var result = Evaluate(statement); 

    // Update the output with the result of the SQL statement 
    output = output.Replace("{" + statement + "}", result); 
} 

這顯然不是這樣做的最有效的方式,但我認爲這充分體現了概念不弄髒的水域。

您需要定義Evaluate(string)方法。這將處理執行SQL。

0

你可能想看看在CodePlex上

http://razorengine.codeplex.com/

剃刀發動機項目

在你的模板中使用SQL等看起來不是一個好主意。我建議你爲每個模板製作一個ViewModel。

剃刀的事情真的很容易使用。只需添加一個參考,導入命名空間,並調用Parse方法,像這樣:

(VB傢伙,所以原諒語法!)

MyViewModel myModel = new MyViewModel("Bob",150.00); //set properties 

string myTemplate = "Dear Mr. @Model.FirstName, Your invoice for this quarter is: @Model.InvoiceAmount"; 

string myOutput = Razor.Parse(myTemplate, myModel); 

你的字符串可以來自任何地方 - 存儲我用這與我的模板在數據庫中,你可以從文件或其他任何東西中加載它。它作爲一個視圖引擎是非常強大的,你可以做條件的東西,循環等等等等。

相關問題