在 .Net 中将 CDATA 节点转换为编码字符串

Convert CDATA node to encoded string in .Net

提问人:freefaller 提问时间:1/27/2023 最后编辑:freefaller 更新时间:1/28/2023 访问量:60

问:

TL;DR - 在 .Net 和 XmlDocument/XDocument 中,有没有一种简单的方法 (XPath?) 来查找节点,以便可以删除它们并对内容进行编码?CDATA

查看详情...

我的系统在很多情况下手动构建XML字符串(例如字符串连接,而不是通过XmlDocument或XDocument构建),这些字符串可能包含多个节点(可以出现在结构的任何级别)...例如<![CDATA[...]]>

<data><one><![CDATA[ab&cd]]></one><two><inner><![CDATA[xy<z]]></inner></two></data>

将此数据存储在 SQLServer XML 列中时,将自动删除 并对内部文本进行编码...这是 SQLServer 的标准,它不“做”。<![CDATA[..]]>CDATA

我的问题是我有复杂的代码,它采用一个类的两个实例,并且审计跟踪它们之间的差异......一个或多个可以是包含 XML 的字符串属性。

当实际上没有任何变化时,这会导致不匹配(因此会导致审计跟踪条目),因为代码创建了一种 XML 格式,而 SQLServer 返回不同的形式,例如......

// Manually generated XML string...
<data><one><![CDATA[ab&cd]]></one><two><inner><![CDATA[xy<z]]></inner></two></data>
// SQLServer returned string...
<data><one>ab&amp;cd</one><two><inner>xy&lt;z</inner></two></data>

在 .Net 中是否有一种简单的方法来处理手动生成的 XML 并将每个节点转换为其编码版本,以便我可以将字符串与 SQLServer 返回的字符串进行比较?CDATA

有没有一个 XPath 可以找到所有这些元素?SelectNodes

(在任何人陈述之前,显而易见的解决方案是首先不要在手动创建 XML 时使用......但是,由于实例数量庞大,这是不可能的。CDATA

C# .NET LINQ-to-XML XMLDocument

评论

0赞 Tu deschizi eu inchid 1/28/2023
由于实例数量众多,这是不可能的:这种说法似乎是一个谬误。这很可能是可能的,只是不可取。
0赞 NetMage 1/28/2023
在转换为方法版本之前,您不能处理XML字符串吗?XmlDocumentXDocumentRegex.Replace
0赞 freefaller 1/30/2023
@NetMage - 正则表达式绝对有它的位置,我确实经常使用它......但是试图用它来解析XML是一个危险的游戏。看看臭名昭著的答案,有人问他们是否可以使用正则表达式解析XHTML
0赞 NetMage 1/31/2023
@freefaller啊,但你不是在解析,而是在尝试转换单个元素。我认为如果注释和字符串碰巧包含CDATA模式,则存在潜在问题,但这似乎不太可能......

答:

2赞 Martin Honnen 1/28/2023 #1

只需一个循环即可轻松实现:foreachReplaceChild

using System.Xml;

var doc = new XmlDocument();
doc.LoadXml(@"<data><one><![CDATA[ab&cd]]></one><two><inner><![CDATA[xy<z]]></inner></two><three><inner>a &lt; b</inner></three></data>");

foreach (var cdata in doc.SelectNodes("//text()").OfType<XmlCDataSection>())
{
   cdata.ParentNode.ReplaceChild(doc.CreateTextNode(cdata.Data), cdata);
}

Console.WriteLine(doc.OuterXml);

输出

<data><one>ab&amp;cd</one><two><inner>xy&lt;z</inner></two><three><inner>a &lt; b</inner></three></data>

另一种选择是使用 XslCompiledTransform 通过 XSLT 身份转换来运行 XML,例如

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

评论

0赞 freefaller 1/30/2023
太好了——谢谢@Martin。我没有想到要测试节点的类型......我正集中精力寻找合适的 xpath。你答案的第一部分是完美的