字符串转义成XML


90

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

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

编辑1:我是串联简单和短期的XML文件,我不使用序列化,所以我需要手动明确转义XML字符,例如,我需要把a<b<foo></foo>,所以我需要逃避串a<b并付诸元素富。


这不是一个单一的方法,而是以下几种方法:http
marcc

15
我能想到的最短的时间:new XText(unescaped).ToString()
sehe 2012年

3
对于其他绊脚石的人,我发现这是最好的答案:stackoverflow.com/a/5304827/1224069
Philip Pittle

Answers:


74
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;
}

5
您甚至不需要将元素附加到文档。但是,我仍然要说一开始最好不要尝试这样做-听起来乔治正在通过手工做事为自己工作……
乔恩·斯凯特

15
我真的不喜欢这个答案,因为它太重了。XmlDocument将使用XmlReader / XmlWriter来完成实际工作,所以为什么不切实际,避免使用繁重的DOM?
Steven Sudit

7
@ Will,OP要求提供一个函数,该函数将转义可以放入XML 元素而非属性中的文本。我的函数不会转义单引号或双引号,因为它们可以放在XML元素中。
Darin Dimitrov

5
@darin好点,应该强调一点。我对这次对话的结果感到满意,并撤回了我的保留。早上好,先生。

1
不知HttpUtility.HtmlEncodeSystem.Web可以安全地使用?
Pooven


38

编辑:您说“我正在串联简单而简短的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。如果不是,请发布更多详细信息。


谢谢乔恩,我在我的原始帖子EDIT 1部分添加了更多细节。谢谢您能给我一些意见和建议。:-)
George2,2009年

“在XML转义之后”-您的意思是?你能用别的话说吗?英语不是我的母语。:-)
George2,2009年

乔恩,您好,如何从XML格式转义为普通的字符串格式,即从输入“ Brackets&amp;&lt;&gt;”,我们得到输出“ Brackets&stuff <>”?
2009年

2
@ George2:您向XElement询问其值,或者向XmlElement询问其InnerText。
乔恩·斯基特

25

感谢@sehe进行单行转义:

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

我在其中添加了单行转义:

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

XText不会转义引号。
MertGülsoy2015年

9

乔治,很简单。始终使用XML API来处理XML。他们为您完成所有的转义和转义。

切勿通过附加字符串来创建XML。


生活的话。有许多XML API选项可用,但是我们都应该同意的一件事是手动字符串连接是不可接受的。
Steven Sudit

尽管我通常对此表示同意,但在某些极少数情况下可能需要手动转义。例如,在使用Roslyn创建XML文档时。
svick

@svick:为什么不使用LINQ to XML创建XML,然后使用.ToString()?
约翰·桑德斯

@JohnSaunders,因为Roslyn有自己的XML类集,例如XmlElementSyntax。而且,您也需要生成该事实,这也使情况变得复杂///。而且我无法将每一行都单独生成XObject,因为这不适用于多行标记。
svick

1
@svick:因此生成xml,全部在一行上,粘贴///在它的前面,然后重新格式化代码。这不是什么大不了的事情,而且肯定是一个极端的案例。如果绝对必要,我敢肯定您可以创建一个自定义XmlWriter样式,以所需的方式进行换行和空格,但要放在///新行的前面。或者,使用XSLT对XML进行漂亮的打印。但无论如何,XML仍应由XML API生成。
约翰·桑德斯

5

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

XmlConvert.EncodeName(string nameToEscape)

它还将转义空格和XML元素的所有无效字符。

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


基于这些问题,我认为他们只需要内部文本。您的解决方案可以工作,但是有点过大,因为它还打算处理元素和属性名称之类的东西。\
Sean Duggan 2014年

好吧,我来到这里试图逃脱节点名称的任何东西,并认为我的发现可以对将来的任何人有所帮助。我也看不到什么是“过大杀伤力”,但没关系。;)
CharlieBrown 2014年

哦,这是有用的信息。:)我只是想指出一点,您可能不会被否决的原因之一是因为人们可能会觉得您没有回答眼前的问题。
肖恩·杜根

链接指向SecurityElement.Escape(String)的文档,这是故意的吗?XmlConvert.EncodeName(String)有它自己的页面。我知道问这个问题已经好几年了,但是我怎么知道要使用哪一个呢?他们不是以不同的方式做同一件事吗?
micnil

4

警告:死灵法术

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

在XML 1.1中,最简单,最安全的方法是对所有内容进行编码。
喜欢&#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
Stefan Steiger

4

基于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"

3

以下功能将完成工作。没有针对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;
        }
    }
}

3

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

public static string XmlEncode(string unescaped)
{
    if (unescaped == null) return null;
    return JsonConvert.SerializeObject(unescaped); ;
}

public static string XmlDecode(string escaped)
{
    if (escaped == null) return null;
    return JsonConvert.DeserializeObject(escaped, typeof(string)).ToString();
}

例:

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.