0

我有一个相当简单的要求。我在 C# 中创建一个 json 对象。我有一些属性是双打的。最初,我创建了 xml 并将这些值格式化为在小数点后有适当数量的尾随零。现在我正在创建 json 和 xml。我正在使用 LINQ to JSON 生成 json。然后我使用 JSONConvert 创建和 XDocument。但问题是,如果我将双精度值作为对象而不是格式化字符串放入 JObject 中,与将其存储为字符串相比,我会丢失尾随零。
这是一些示例代码:

double value = 1.0;
string stringVal = "1.000";
JObject test = new JObject(new JProperty("sta", new JObject(
        new JProperty("@valDouble", value),
        new JProperty("@valString", stringVal)
        )));
var testXml = JsonConvert.DeserializeXNode(test.ToString());

我意识到我可以通过我创建的 JObjects 并提取值并使用代码手动将其格式化为字符串。但是有什么方法可以让转换器以某种格式处理值。所以而不是得到

<sta valDouble="1" valString="1.000">
</sta>

我想得到,

<sta valDouble="1.000" valString="1.000">
</sta>

我希望我已经很好地解释了这个问题。我已经查看了 Deserialize 方法,但它们只是有其他选项来选择根元素名称以及是否编写数组属性。在这种情况下,他们没有帮助我。

4

1 回答 1

0

好的,我实际上已经找到了解决方案,但它需要 XmlNodeConverter 的修改版本。为了保持我的影响很小,我实际上对实际代码进行了最小的更改,然后创建了一个派生类。

//added this virtual method
protected virtual string GetAttributeValue(string attributeName, JsonReader reader)
{
    return reader.Value.ToString();
}

private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, XmlNamespaceManager manager)
{
  if (string.IsNullOrEmpty(propertyName))
    throw new JsonSerializationException("XmlNodeConverter cannot convert JSON with an empty property name to XML.");

  Dictionary<string, string> attributeNameValues = ReadAttributeElements(reader, manager);

  string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);

  if (propertyName.StartsWith("@"))
  {
    var attributeName = propertyName.Substring(1);
    //Made the change below to use the new method
    //var attributeValue = reader.Value.ToString();
    var attributeValue = GetAttributeValue(attributeName, reader);
    ...

// Modified to virtual to allow derived class to override.  Added attributeName parameter
protected virtual string ConvertTokenToXmlValue(string attributeName, JsonReader reader)
{
  if (reader.TokenType == JsonToken.String)
  {
    return reader.Value.ToString();
  }
  ....

然后我创建了以下派生的 xml 节点转换器。

public class DerivedXmlNodeConverter : Newtonsoft.Json.Converters.XmlNodeConverter
{
private Dictionary<string, string> _attributeFormatStrings;
public Dictionary<string, string> AttributeFormatStrings
{
    get
    {
        if (_attributeFormatStrings == null)
            _attributeFormatStrings = new Dictionary<string,string>();
        return _attributeFormatStrings;
    }
}
protected override string GetAttributeValue(string attributeName, JsonReader reader)
{
    Console.WriteLine("getting attribute value: " + attributeName);
    if (AttributeFormatStrings.ContainsKey(attributeName))
    {
        return string.Format(AttributeFormatStrings[attributeName], reader.Value);
    }
    else
        return base.GetAttributeValue(attributeName, reader);
}
protected override string ConvertTokenToXmlValue(string attributeName, JsonReader reader)
{
    if (AttributeFormatStrings.ContainsKey(attributeName))
    {
        return string.Format(AttributeFormatStrings[attributeName], reader.Value);
    }
    else
        return base.ConvertTokenToXmlValue(attributeName, reader);
} 
}

然后我不得不复制 JsonConvert.DeserializeXNode 所做的代码。

    DerivedXmlNodeConverter derived = new DerivedXmlNodeConverter();
    derived.WriteArrayAttribute = false;
    derived.DeserializeRootElementName = null;
    derived.AttributeFormatStrings["valDouble"] = "{0:0.000}";
    JsonSerializerSettings settings = new JsonSerializerSettings { Converters = new JsonConverter[] { derived } };
    StringReader sr = new StringReader(test.ToString(Newtonsoft.Json.Formatting.Indented));
    JsonReader reader = new JsonTextReader(sr);
    JsonSerializer ser = JsonSerializer.CreateDefault(settings);
    ser.CheckAdditionalContent = true;
    XDocument intoXml = (XDocument)(ser.Deserialize(reader, typeof(XDocument)));

我认为这些在 Newtownsoft 框架中会有很大的变化——允许这些钩子进行定制。我希望这段代码可以帮助其他需要它的人。

-大卫

于 2013-07-30T14:25:24.793 回答