在 .NET 中使用 XmlReader 取消转义 XML 实体?

Posted

技术标签:

【中文标题】在 .NET 中使用 XmlReader 取消转义 XML 实体?【英文标题】:Unescaping XML entities using XmlReader in .NET? 【发布时间】:2011-07-15 07:53:14 【问题描述】:

我正在尝试在 .NET (C#) 中对字符串中的 XML 实体进行转义,但我似乎无法使其正常工作。

例如,如果我有字符串AT&T,它应该被翻译成AT&T

一种方法是使用 HttpUtility.htmlDecode(),但这是针对 HTML。

所以我对此有两个问题:

    使用 HttpUtility.HtmlDecode() 解码 XML 实体是否安全?

    如何使用 XmlReader(或类似的东西)来做到这一点?我尝试了以下方法,但总是返回一个空字符串:

    static string ReplaceEscapes(string text)
    
        StringReader reader = new StringReader(text);
    
        XmlReaderSettings settings = new XmlReaderSettings();
    
        settings.ConformanceLevel = ConformanceLevel.Fragment;
    
        using (XmlReader xmlReader = XmlReader.Create(reader, settings))
        
            return xmlReader.ReadString();
        
    
    

【问题讨论】:

【参考方案1】:

HTML 转义和 XML 密切相关。正如您所说,HttpUtility 同时具有 HtmlEncodeHtmlDecode 方法。这些也将在 XML 上运行,因为只有少数实体需要转义:<>\'& 在 HTML 和 XML 中。

使用HttpUtility 类的缺点是您需要引用System.Web dll,这也带来了许多您可能不想要的其他内容。

特别是对于 XML,SecurityElement 类有一个将进行编码的 Escape 方法,但没有相应的 Unescape 方法。因此,您有几个选择:

    使用HttpUtility.HtmlDecode() 并忍受对System.Web 的引用

    滚动您自己的解码方法来处理特殊字符(因为只有少数 - 查看 Reflector 中 SecurityElement 的静态构造函数以查看完整列表)

    使用(hacky)解决方案,例如:

.

    public static string Unescape(string text)
    
        XmlDocument doc = new XmlDocument();
        string xml = string.Format("<dummy>0</dummy>", text);
        doc.LoadXml(xml);
        return doc.DocumentElement.InnerText;
    

就个人而言,如果我已经引用了System.Web,我会使用HttpUtility.HtmlDecode(),如果没有,我会使用我自己的。我不喜欢你的XmlReader 方法,因为它是Disposable,这通常表明它正在使用需要处置的资源,因此可能是一项昂贵的操作。

【讨论】:

【参考方案2】:

您的#2 解决方案可以工作,但您需要在ReadString 之前致电xmlReader.Read();(或xmlReader.MoveToContent();)。

我猜#1 也是可以接受的,即使有像 &amp;reg; 这样的边缘情况,它是一个有效的 HTML 实体,但不是一个 XML 实体——你的 unescaper 应该如何处理它?将异常作为适当的 XML 解析器抛出,还是像 HTML 解析器那样只返回“®”?

【讨论】:

添加xmlReader.MoveToContent() 成功了,这正是我正在寻找的解决方案。由于 HTML 和 XML 之间的差异,我真的不想使用 HttpUtility,所以您的回复非常有帮助。【参考方案3】:

这行得通:

using (XmlReader xmlReader = XmlReader.Create(reader, settings))

    if (xmlReader.Read())
    
       return xmlReader.ReadString();
    

【讨论】:

【参考方案4】:

如果您的输入文本以某些空白字符(如回车符)结尾,我发现最佳答案有一个小错误。

字符串“Testing ”失去它的尾随空白。

如果您将问题中的解决方案与 adrianbanks 的包装标签结合起来,您会得到以下结果。

public static string UnescapeUnicode(string line)
    
        using (StringReader reader = new StringReader("<a>" + line + "</a>"))
        
            using (XmlReader xmlReader = XmlReader.Create(reader))
            
                xmlReader.MoveToContent();
                return xmlReader.ReadElementContentAsString();
            
        
    

【讨论】:

【参考方案5】:

这也有效,并且代码最少:

    public static string DecodeString(string encodedString)
    
        if (string.IsNullOrEmpty(formattedText))
            return string.Empty;
        XmlTextReader xtr = new XmlTextReader(encodedString, XmlNodeType.Element, null);
        if (xtr.Read())
            return xtr.ReadString();
        throw new Exception("Error decoding xml string : " + encodedString);
    

Update1:​​嗯,如果 encodeString 为 "" 似乎不起作用,那么 xtr.Read() 返回 false。

Update2:添加了解决方法

Update3:这似乎效果更好

    public static string DecodeString(string encodedString)
    
        XmlTextReader xtr = new XmlTextReader(encodedString, XmlNodeType.Element, null);
        xtr.MoveToContent();
        return xtr.Value;
    

【讨论】:

以上是关于在 .NET 中使用 XmlReader 取消转义 XML 实体?的主要内容,如果未能解决你的问题,请参考以下文章

在 XmlReader .NET 4.0 中加载失败目录文件

如何在 .Net 2.0/C# 中将 StreamReader 转换为 XMLReader 对象

从 XmlDocument 到 XmlReader .Net

XmlReader - 自关闭元素不会触发 EndElement 事件?

取消转义字符串中的 unicode

在 Java 中取消转义 JavaScript 转义值