【问题标题】:String escape into XML字符串转义到 XML
【发布时间】:2010-11-11 01:48:47
【问题描述】:

是否有任何 C# 函数可用于转义和取消转义字符串,可用于填充 XML 元素的内容?

我正在使用 VSTS 2008 + C# + .Net 3.0。

编辑1:我是拼接简单又短的XML文件,我不使用序列化,所以我需要手动显式转义XML字符,例如我需要把a<b放到<foo></foo>中,所以我需要转义字符串 a<b 并将其放入元素 foo 中。

【问题讨论】:

标签: c# .net xml visual-studio-2008 escaping


【解决方案1】:

【讨论】:

  • 此答案转义引号,与所选答案不同。
  • 这个答案似乎不适用于像 �这样的无效字符
  • 这个答案不完整。它只回答了一半的问题。
  • 同意上述 cmets - 不完整且并非 100% 准确。
  • 取消隐藏:text = System.Security.SecurityElement.FromString(xmlContent).Text;
【解决方案2】:
public static string XmlEscape(string unescaped)
{
    XmlDocument doc = new XmlDocument();
    XmlNode node = doc.CreateElement("root");
    node.InnerText = unescaped;
    return node.InnerXml;
}

public static string XmlUnescape(string escaped)
{
    XmlDocument doc = new XmlDocument();
    XmlNode node = doc.CreateElement("root");
    node.InnerXml = escaped;
    return node.InnerText;
}

【讨论】:

  • 您甚至不需要将元素附加到文档中。但是,我仍然要说,最好不要一开始就尝试这样做——听起来乔治是在为自己做手工……
  • 我真的不喜欢这个答案,因为它太重了。 XmlDocument 将使用 XmlReader/XmlWriter 来完成真正的工作,那么为什么不切入正题,避免使用繁重的 DOM?
  • @Will,OP 要求提供一个函数来转义可以放入 XML element 而不是属性的文本。我的函数不会转义单引号或双引号,因为它们可以放在 XML 元素中。
  • @darin 好点,应该强调的一点。我对这次谈话的结果感到满意,并撤回了我的保留意见。美好的一天,先生。
  • 我想知道System.Web中的HttpUtility.HtmlEncode是否可以安全使用?
【解决方案3】:

编辑:您说“我正在连接简单而短的 XML 文件,并且我不使用序列化,所以我需要手动显式转义 XML 字符”。

我会强烈建议您不要手动操作。使用 XML API 为您完成所有工作 - 读取原始文件,根据需要将两者合并到一个文档中(您可能希望使用 XmlDocument.ImportNode),然后再次将其写出。您不想编写自己的 XML 解析器/格式化程序。序列化在这里有些无关紧要。

如果您能给我们一个简短但完整的示例,说明您正在尝试做什么,我们可能会帮助您避免一开始就担心逃跑。


原答案

您的意思并不完全清楚,但通常 XML API 会为您执行此操作。您在节点中设置文本,它会自动转义它需要的任何内容。例如:

LINQ to XML 示例:

using System;
using System.Xml.Linq;

class Test
{
    static void Main()
    {
        XElement element = new XElement("tag",
                                        "Brackets & stuff <>");

        Console.WriteLine(element);
    }
}

DOM 示例:

using System;
using System.Xml;

class Test
{
    static void Main()
    {
        XmlDocument doc = new XmlDocument();
        XmlElement element = doc.CreateElement("tag");
        element.InnerText = "Brackets & stuff <>";
        Console.WriteLine(element.OuterXml);
    }
}

两个示例的输出:

<tag>Brackets &amp; stuff &lt;&gt;</tag>

当然,这是假设您希望 XML 转义。如果不是,请发布更多详细信息。

【讨论】:

  • 感谢乔恩,我已将更多详细信息放入我原来的帖子编辑 1 部分。感谢您能给我一些cmets和建议。 :-)
  • “XML 转义后”——你的意思是?请你换个说法好吗?英语不是我的母语。 :-)
  • 嗨 Jon,如何从 XML 格式转义为普通字符串格式,即从输入“Brackets & stuff <>”,我们得到输出“Brackets & stuff ”?
  • @George2:您向 XElement 询问其值,或向 XmlElement 询问其 InnerText。
【解决方案4】:

感谢@sehe 的单行转义:

var escaped = new System.Xml.Linq.XText(unescaped).ToString();

我添加了一行 un-escape:

var unescapedAgain = System.Xml.XmlReader.Create(new StringReader("<r>" + escaped + "</r>")).ReadElementString();

【讨论】:

  • XText 不会转义引号。
【解决方案5】:

如果您想像我发现这个问题时一样转义 XML 节点名称,例如从 XML 序列化读取时,请使用最简单的方法:

XmlConvert.EncodeName(string nameToEscape)

它还会为 XML 元素转义空格和任何无效字符。

http://msdn.microsoft.com/en-us/library/system.security.securityelement.escape%28VS.80%29.aspx

【讨论】:

  • 我认为,根据问题,他们只想要内部文本。您的解决方案可以工作,但有点矫枉过正,因为它还打算处理元素和属性名称等内容。\
  • 好吧,我来到这里试图逃避节点名称,并认为我的发现可以在未来帮助任何人。我也看不出什么是“矫枉过正”,但没关系。 ;)
  • 哦,这是有用的信息。 :) 我只是想指出,您可能没有得到支持的原因之一是人们可能会觉得您没有回答手头的问题。
  • 链接指向 SecurityElement.Escape(String) 的文档,这是故意的吗? XmlConvert.EncodeName(String) 有它自己的页面。我知道自从有人问这个问题以来已经有几年了,但是我怎么知道该使用哪一个呢?他们不是做同样的事情,但方式不同吗?
  • @CharlieBrown:也许您还想从中创建一个单独的问题并回答它,以便人们更好地找到它。感谢发布!
【解决方案6】:

乔治,这很简单。始终使用 XML API 来处理 XML。他们为你做所有的逃避和逃避。

永远不要通过附加字符串来创建 XML。

【讨论】:

  • 生活的话。有许多可用的 XML API 选项,但我们都应该同意的一件事是手动字符串连接是不可接受的。
  • 虽然我大体上同意这一点,但在极少数情况下可能需要手动转义。例如,在使用 Roslyn 创建 XML 文档时。
  • @svick:为什么不使用 LINQ to XML 创建 XML,然后使用 .ToString()?
  • @JohnSaunders,因为 Roslyn 有自己的一组 XML 类,例如 XmlElementSyntax。而且您还需要生成///,这也使事情变得复杂。而且我无法将每一行生成为单独的XObject,因为这不适用于多行标签。
  • @svick: 所以生成xml,全部在一行,在前面贴上///,然后重新格式化代码。没什么大不了的,当然也是一个极端的案例。如果绝对有必要,我相信您可以创建一个自定义的 XmlWriter 以按照您喜欢的方式进行换行和空格,但将 /// 放在新行的前面。或者,使用 XSLT 漂亮地打印 XML。但无论如何,XML 仍应由 XML API 生成。
【解决方案7】:

另一个基于 John Skeet 的回答 不返回标签

void Main()
{
    XmlString("Brackets & stuff <> and \"quotes\"").Dump();
}

public string XmlString(string text)
{
    return new XElement("t", text).LastNode.ToString();
} 

这仅返回传入的值,采用 XML 编码格式:

Brackets &amp; stuff &lt;&gt; and "quotes"

【讨论】:

    【解决方案8】:

    警告:死灵法

    Darin Dimitrov 的回答 + System.Security.SecurityElement.Escape(string s) 仍然不完整。

    在 XML 1.1 中,最简单、最安全的方法就是对所有内容进行编码。
    喜欢 &amp;#09; 的 \t。
    XML 1.0 根本不支持它。
    对于 XML 1.0,一种可能的解决方法是对包含字符的文本进行 base-64 编码。

    //string EncodedXml = SpecialXmlEscape("привет мир");
    //Console.WriteLine(EncodedXml);
    //string DecodedXml = XmlUnescape(EncodedXml);
    //Console.WriteLine(DecodedXml);
    public static string SpecialXmlEscape(string input)
    {
        //string content = System.Xml.XmlConvert.EncodeName("\t");
        //string content = System.Security.SecurityElement.Escape("\t");
        //string strDelimiter = System.Web.HttpUtility.HtmlEncode("\t"); // XmlEscape("\t"); //XmlDecode("&#09;");
        //strDelimiter = XmlUnescape("&#59;");
        //Console.WriteLine(strDelimiter);
        //Console.WriteLine(string.Format("&#{0};", (int)';'));
        //Console.WriteLine(System.Text.Encoding.ASCII.HeaderName);
        //Console.WriteLine(System.Text.Encoding.UTF8.HeaderName);
    
    
        string strXmlText = "";
    
        if (string.IsNullOrEmpty(input))
            return input;
    
    
        System.Text.StringBuilder sb = new StringBuilder();
    
        for (int i = 0; i < input.Length; ++i)
        {
            sb.AppendFormat("&#{0};", (int)input[i]);
        }
    
        strXmlText = sb.ToString();
        sb.Clear();
        sb = null;
    
        return strXmlText;
    } // End Function SpecialXmlEscape
    

    XML 1.0:

    public static string Base64Encode(string plainText)
    {
        var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
        return System.Convert.ToBase64String(plainTextBytes);
    }
    
    public static string Base64Decode(string base64EncodedData)
    {
        var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
        return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
    }
    

    【讨论】:

    • 那么在 XML 1.1 中,如何转义所有内容?
    • @Philip Pittle:见 SpecialXmlEscape
    【解决方案9】:

    以下功能将完成工作。没有针对 XmlDocument 进行测试,但我想这要快得多。

    public static string XmlEncode(string value)
    {
        System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings 
        {
            ConformanceLevel = System.Xml.ConformanceLevel.Fragment
        };
    
        StringBuilder builder = new StringBuilder();
    
        using (var writer = System.Xml.XmlWriter.Create(builder, settings))
        {
            writer.WriteString(value);
        }
    
        return builder.ToString();
    }
    
    public static string XmlDecode(string xmlEncodedValue)
    {
        System.Xml.XmlReaderSettings settings = new System.Xml.XmlReaderSettings
        {
            ConformanceLevel = System.Xml.ConformanceLevel.Fragment
        };
    
        using (var stringReader = new System.IO.StringReader(xmlEncodedValue))
        {
            using (var xmlReader = System.Xml.XmlReader.Create(stringReader, settings))
            {
                xmlReader.Read();
                return xmlReader.Value;
            }
        }
    }
    

    【讨论】:

      【解决方案10】:

      使用第三方库 (Newtonsoft.Json) 作为替代方案:

      public static string XmlEscape(string unescaped)
      {
          if (unescaped == null) return null;
          return JsonConvert.SerializeObject(unescaped); ;
      }
      
      public static string XmlUnescape(string escaped)
      {
          if (escaped == null) return null;
          return JsonConvert.DeserializeObject(escaped, typeof(string)).ToString();
      }
      

      转义字符串示例:

      a&lt;b ==> "a&amp;lt;b"

      &lt;foo&gt;&lt;/foo&gt; ==> "foo&amp;gt;&amp;lt;/foo&amp;gt;"

      注意: 在较新的版本中,上面编写的代码可能无法使用转义,因此您需要指定字符串的转义方式:

      public static string XmlEscape(string unescaped)
      {
          if (unescaped == null) return null;
          return JsonConvert.SerializeObject(unescaped, new JsonSerializerSettings()
          {
              StringEscapeHandling = StringEscapeHandling.EscapeHtml
          });
      }
      

      转义字符串示例:

      a&lt;b ==> "a\u003cb"

      &lt;foo&gt;&lt;/foo&gt; ==> "\u003cfoo\u003e\u003c/foo\u003e"

      【讨论】:

      • 这会生成 JSON 而不是 XML?
      • 这只会生成转义字符串。实际上,这些函数可用于“转义”和“取消转义”输入字符串。用于转义的输入字符串可能是 ex。 HTML 或 XML。我已更改函数名称以使其更正确。
      • 但是 XML 不应该在该函数产生的字符串周围有引号。此外,并非所有字符都以 XML 兼容的形式进行转义。例如选项卡被格式化为“\t”。
      • 另外,能否请您指出一个能够读取 \uxxxx 形式的字符的 XML 解析函数?
      • 这适用于 JSON,而不是 XML。 XML 有更多特殊字符,例如 &amp;,这些字符将被遗漏
      【解决方案11】:

      SecurityElementEscape 为您完成这项工作

      在使用 SecurityElement 中的字符串之前,使用此方法替换字符串中的无效字符。如果在 SecurityElement 中使用了无效字符而没有进行转义,则会引发 ArgumentException。

      下表显示了无效的 XML 字符及其转义等效项。

      https://docs.microsoft.com/en-us/dotnet/api/system.security.securityelement.escape?view=net-5.0

      【讨论】:

      猜你喜欢
      • 2011-05-26
      • 2014-04-10
      • 2012-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-08
      • 1970-01-01
      相关资源
      最近更新 更多