【问题标题】:Change property value while converting from XML to JSON从 XML 转换为 JSON 时更改属性值
【发布时间】:2015-05-15 00:56:37
【问题描述】:

在一个项目中,我使用 TSQL FOR XML 从 DB 获取一些数据。在所有表中,日期字段的最小值都设置为 01/01/1900

这是因为 null 值不允许作为无法更改的内部政治。

使用 xml 结果,我需要将其转换为 JSON 并将其序列化到客户端。

为此,我正在使用:

string jSonString = Newtonsoft.Json.JsonConvert.SerializeXmlNode(xmlDoc, Newtonsoft.Json.Formatting.None, true);

好;现在我需要在转换为 JSON 时将每个 01/01/1900 日期转换为 DateTime.MinValue (01/01/0001);我该如何处理?

【问题讨论】:

  • 这听起来像是数据库中的糟糕设计 - 那些日期列应该为 null 以表示没有日期,而不是 01/01/1900 - 我会先纠正它。
  • @TrevorPilley 我知道,但不允许空值作为无法更改的内部政治。添加到问题中。

标签: c# json.net


【解决方案1】:

更新 - 修改后的代码适用于任何具有 01/01/1900 值的节点/属性。

我会在转换为 JSON 之前处理 XML 文档。如果您的日期值是节点或属性值,这是 LinqPad 示例。因为我不知道你的 XML 数据结构只是简单的例子:

void Main()
{
    // IF IT IS NODE VALUE
    var xml = @"<data>
        <objectA>
            <dateValueA>01/01/1900</dateValueA>
            <dateValueB>01/01/1971</dateValueB>
        </objectA>
        <objectB>
            <dateValueA>01/01/2002</dateValueA>
            <dateValueB>01/01/1900</dateValueB>
            <dateValueZ>01/01/2011</dateValueZ>
        </objectB>
        <objectC>
            <dateValueA>01/01/1910</dateValueA>
            <dateValueB>01/01/2012</dateValueB>
            <dateValueC>01/01/1900</dateValueC>
        </objectC>
    </data>";

    var xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(xml);

    var nodes = xmlDoc.SelectNodes("//*[text()='01/01/1900']");
    foreach(XmlNode node in nodes)
    {
        node.InnerText = "01/01/0001";
    }

    string jSonString = Newtonsoft.Json.JsonConvert.SerializeXmlNode(xmlDoc, Newtonsoft.Json.Formatting.None, true);

    "// IF IT IS NODE VALUE - RESULTS".Dump();
    jSonString.Dump();

    // IF IT IS ATTRIBUTE VALUE
    var xmlAttr = @"<data>
        <objectA dateValueA='01/01/1900' dateValueB='01/01/1900' dateValueC='01/01/2011' />
        <objectB dateValueB='01/01/2011' someOtherDate='01/01/1900' />
        <objectC dateValueC='01/01/1900' dontChangeThisDate='05/04/1923' />
    </data>";

    var xmlDocAttr = new XmlDocument();
    xmlDoc.LoadXml(xmlAttr);

    var nodesAttr = xmlDoc.SelectNodes("//*[@*='01/01/1900']");
    for(var i=0; i < nodesAttr.Count; i++)
    {
        foreach(XmlAttribute attrib in nodesAttr[i].Attributes)
        {
            if (attrib.Value == "01/01/1900")
            {
                attrib.Value = "01/01/0001";
            }
        }
    }

    string jSonStringAttr = Newtonsoft.Json.JsonConvert.SerializeXmlNode(xmlDoc, Newtonsoft.Json.Formatting.None, true);

    "// IF IT IS ATTRIBUTE VALUE - RESULTS".Dump();
    jSonStringAttr.Dump();

}

结果:

// IF IT IS NODE VALUE - RESULTS
{"objectA":{"dateValueA":"01/01/0001","dateValueB":"01/01/1971"},"objectB":{"dateValueA":"01/01/2002","dateValueB":"01/01/0001","dateValueZ":"01/01/2011"},"objectC":{"dateValueA":"01/01/1910","dateValueB":"01/01/2012","dateValueC":"01/01/0001"}}

// IF IT IS ATTRIBUTE VALUE - RESULTS
{"objectA":{"@dateValueA":"01/01/0001","@dateValueB":"01/01/0001","@dateValueC":"01/01/2011"},"objectB":{"@dateValueB":"01/01/2011","@someOtherDate":"01/01/0001"},"objectC":{"@dateValueC":"01/01/0001","@dontChangeThisDate":"05/04/1923"}}

这对你有用吗?

【讨论】:

  • 我不能这样处理问题;我的函数必须是通用的(用于某些 SP)并且我无法以编程方式知道 DateTime 列的名称
  • @IrvinDominin 我更新了代码以使用任何具有值01/01/1900 的节点或属性名称。这行得通吗?
  • 唯一的副作用是包含该值的字符串也会被转换。而且我有点担心在中等长度的 xml 上运行正则表达式会很昂贵
  • @IrvinDominin 这不正确。上面的示例不会更改字符串内部的值,它与节点或属性的值完全匹配。我也不确定您对“成本昂贵”的担忧。您必须扫描整个文档才能找到需要替换的值。我很想知道你最终会做什么,因为这是一个很好的问题,我想知道以供将来使用。
  • 最后我使用这个解决方案,在我的测试中成本并不昂贵。谢谢!
【解决方案2】:

如果您控制 T-SQL,您可以尝试替换查询中的值:

CASE   
    WHEN [DateWhichCantBeNull] = '1900-01-01'
        THEN '0001-01-01'
    ELSE [DateWhichCantBeNull]
END AS "DateWhichCantBeNull"

您可能需要将其转换为DateTime2,如果它仍然需要是序列化正常工作的真实日期。

【讨论】:

  • 这是我的第一个想法,但我正在使用的 SP 无法更改。我知道这种结构有一些限制......
猜你喜欢
  • 2021-10-26
  • 2018-07-23
  • 1970-01-01
  • 2016-08-09
  • 2016-10-18
  • 1970-01-01
  • 2020-03-12
  • 2016-11-11
  • 2016-10-26
相关资源
最近更新 更多