JSON形式でクエリの結果を返すASP.Net Webハンドラーがあります。
public static String dt2JSON(DataTable dt)
{
String s = "{\"rows\":[";
if (dt.Rows.Count > 0)
{
foreach (DataRow dr in dt.Rows)
{
s += "{";
for (int i = 0; i < dr.Table.Columns.Count; i++)
{
s += "\"" + dr.Table.Columns[i].ToString() + "\":\"" + dr[i].ToString() + "\",";
}
s = s.Remove(s.Length - 1, 1);
s += "},";
}
s = s.Remove(s.Length - 1, 1);
}
s += "]}";
return s;
}
問題は、返されるデータに引用符が含まれていることがあり、jsオブジェクトに適切に作成できるようにこれらをjavascriptエスケープする必要があることです。データ内で引用符を見つけ(引用符が毎回存在しない)、それらの前に「/」文字を配置する方法が必要です。
応答テキストの例(間違った):
{"rows":[{"id":"ABC123","length":"5""},
{"id":"DEF456","length":"1.35""},
{"id":"HIJ789","length":"36.25""}]}
「」をエスケープする必要があるため、私の応答は次のようになります。
{"rows":[{"id":"ABC123","length":"5\""},
{"id":"DEF456","length":"1.35\""},
{"id":"HIJ789","length":"36.25\""}]}
また、私はC#にかなり慣れていないので(実際にはコーディング全般)、コード内の何か他のものが愚かに見える場合はお知らせください。
.net 4.0以降には、標準のHttpUtility.JavaScriptStringEncode
Lone Coderによって記述された初期の西風ソリューションについては非常にいいです
http://www.west-wind.com/weblog/posts/114530.aspx で見つけた効率的で堅牢な方法を次に示します。
/// <summary>
/// Encodes a string to be represented as a string literal. The format
/// is essentially a JSON string.
///
/// The string returned includes outer quotes
/// Example Output: "Hello \"Rick\"!\r\nRock on"
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string EncodeJsString(string s)
{
StringBuilder sb = new StringBuilder();
sb.Append("\"");
foreach (char c in s)
{
switch (c)
{
case '\"':
sb.Append("\\\"");
break;
case '\\':
sb.Append("\\\\");
break;
case '\b':
sb.Append("\\b");
break;
case '\f':
sb.Append("\\f");
break;
case '\n':
sb.Append("\\n");
break;
case '\r':
sb.Append("\\r");
break;
case '\t':
sb.Append("\\t");
break;
default:
int i = (int)c;
if (i < 32 || i > 127)
{
sb.AppendFormat("\\u{0:X04}", i);
}
else
{
sb.Append(c);
}
break;
}
}
sb.Append("\"");
return sb.ToString();
}
JavaScriptSerializerクラスを見る必要があると思います。ずっと安定しており、あらゆる種類のデータやエスケープ文字などを正しく処理します。また、コードはずっときれいに見えます。
あなたの場合、クラスは次のようになります。
public static String dt2JSON(DataTable dt) {
var rows = new List<Object>();
foreach(DataRow row in dt.Rows)
{
var rowData = new Dictionary<string, object>();
foreach(DataColumn col in dt.Columns)
rowData[col.ColumnName] = row[col];
rows.Add(rowData);
}
var js = new JavaScriptSerializer();
return js.Serialize(new { rows = rows });
}
このメソッドは、正しくシリアル化されたJSON文字列を返します...たとえば、sthは次のようになります。
{"rows":[{"id":1,"name":"hello"},{"id":2,"name":"bye"}]}
楽しんで! :)
Javascriptの文字列リテラルを正しくエスケープするには、最初にすべてのバックスラッシュ文字をエスケープしてから、引用符(または文字列区切り文字として使用する場合はアポストロフィ)をエスケープします。
だから、あなたが必要なのは:
value.Replace("\\","\\\\").Replace("\"","\\\"")
私に飛び出すのは、ループで文字列連結を使用しているということです。スケーリングが非常に悪いため、これは悪いことです。 + =演算子は、既存の文字列の末尾に文字を追加しません(文字列は不変であり、変更できないため)。代わりに、文字列と追加された文字を新しい文字列にコピーします。毎回より多くのデータをコピーすると、eEveryの追加行はメソッドの実行時間を約2倍にします。代わりに、StringBuilderを使用して文字列を作成します。
ColumnName
メソッドではなく、ToString
プロパティを使用して列の名前を取得します。 ToString
メソッドは、設定されている場合はExpression
プロパティ値を返します。設定されていない場合のみ、ColumnName
プロパティを返します。
public static String dt2JSON(DataTable dt) {
StringBuilder s = new StringBuilder("{\"rows\":[");
bool firstLine = true;
foreach (DataRow dr in dt.Rows) {
if (firstLine) {
firstLine = false;
} else {
s.Append(',');
}
s.Append('{');
for (int i = 0; i < dr.Table.Columns.Count; i++) {
if (i > 0) {
s.Append(',');
}
string name = dt.Columns[i].ColumnName;
string value = dr[i].ToString();
s.Append('"')
.Append(name.Replace("\\","\\\\").Replace("\"","\\\""))
.Append("\":\"")
.Append(value.Replace("\\","\\\\").Replace("\"","\\\""))
.Append('"');
}
s.Append("}");
}
s.Append("]}");
return s.ToString();
}
なぜあなたはこれをしないのですか:
string correctResponseText = wrongResponseText.Replace("\"", "\\\"");
string.Replace(<mystring>, @"\"", @"\\"");
C#からhtmlタグに文字列を送信する必要がある場合に機能します。
<buton onlick="alert('<< here >>')" />
HttpUtility.HtmlEncode