如何防止XMLReader对字符进行反转义

3
我希望创建一个简单的XMLreader,可以将完整的节点(包括子节点)作为文本读取:
string TXML = @"<xml><text>hall&#xF6;le</text></xml>";

XmlReader r = XmlReader.Create(new StringReader(TXML));
r.Read(); r.Read();

string o = r.ReadOuterXml();

ReadOuterXml可以完成任务,但它会取消转义已经转义的符号:

"<text>hallöle</text>"

I whish to have the result:

"<text>hall&#xF6;le</text>"

我该如何避免这种“取消转义”的情况。我想将这些片段存储到数据库中,不需要进行转义。此外,我不想解析和重新创建这些片段。


1
你能否修改XML源代码,将&符号转义为&amp; - Chris Sinclair
当您将数据插入数据库时,我认为您希望它是正确的数据,而不是转义后的数据。这样,您就可以搜索它,并且当您从数据库中读取数据时,它将是正确的。如果您正在使用ADO和参数,则在将数据插入数据库时不需要转义数据。 - Steven Doggart
我是中间人。我不能更改源代码。此外,如果我将存储的数据返回给客户端,他希望再次进行转义。这就是为什么我想让它保持原样的原因。 - user1410404
4个回答

3

我遇到了类似的问题,我想在读取xml时保留转义字符,但是在调用ReadOuterXml()时,只有一些字符被保留,至少一个字符被转换了(我有"而不是&quot;)

我的解决方案如下:

string TXML = @"<xml><text>hall&#xF6;le</text></xml>";
TXML = TXML.Replace("&", "&amp;");
XmlTextReader r = new XmlTextReader(new StringReader(TXML));
r.Read(); r.Read();
// now we are at the text element
r.ReadStartElement()
var content = SecurityElement.Escape(r.ReadContentAsString())
r.ReadEndElement()

2
我发现了两个解决方案。两个都不太好,但也许你可以告诉我哪个缺点更少。
这两个解决方案都依赖于直接使用 ´XmlTextReader´ 而不是 ´XmlReader´。它带有属性 ´LinePosition',这导致了第一个解决方案,并以方法 ´ReadChars´ 为基础的第二个解决方案。
解决方案(1),通过索引从原始字符串获取数据
问题:
  • 无法在流输入上工作
  • 如果 XML 有多行,则无法工作
代码
string TXML = @"<xml><data></data><rawnode at=""10 4""><text>hall&#xF6;le</text><z d=""2"">3</z></rawnode><data></data></xml>";

//XmlReader r = XmlReader.Create(new StringReader(TXML));
XmlTextReader r = new XmlTextReader(new StringReader(TXML));

// read to node which shall be retrived "raw"
while ( r.Read() )
{
    if ( r.Name.Equals("rawnode") )
        break;
}

// here we start
int Begin = r.LinePosition;
r.Skip();
int End = r.LinePosition;

// get it out
string output=TXML.Substring(Begin - 2, End - Begin);

解决方案(2),使用´ReadChars´获取数据

问题:

  • 我必须解析并重新创建我想要读取的标记的“外部”标记。
  • 这可能会耗费性能。
  • 我可能会引入错误。

代码:

// ... again create XmlTextReader and read to rawnode, then:
// here we start
int buflen = 15;
char[] buf = new char[buflen];
StringBuilder sb= new StringBuilder("<",20);

//get start tag and attributes    
string tagname=r.Name;
sb.Append(tagname);
bool hasAttributes = r.MoveToFirstAttribute();
while (hasAttributes)
{
    sb.Append(" " + r.Name + @"=""" + r.Value + @"""");
    hasAttributes = r.MoveToNextAttribute();
}
sb.Append(@">");
r.MoveToContent();

//get raw inner data    
int cnt;
while ((cnt = r.ReadChars(buf, 0, buflen)) > 0)
{
    if ( cnt<buflen )
        buf[cnt]=(char)0;
    sb.Append(buf);
}

//append end tag    
sb.Append("</" + tagname + ">");

// get it out
string output = sb.ToString();

1
请查看您的 XML 标头并验证它是否包含类似以下内容:<?xml version="1.0" encoding="ISO-8859-9"?> 对于转义和反转义,您可以使用 C# 函数InnerXmlInnerText
public static string XmlEscape(string unescaped)
{
    XmlDocument doc = new XmlDocument();
    var node = doc.CreateElement("root");
    node.InnerText = unescaped;
    return node.InnerXml;
}

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

1
“string TXML = @”<?xml version=”1.0″ encoding=”ISO-8859-9″?><xml><text>hallöle</text></xml>”;”,但使用相同的代码解析该字符串并没有改变结果。 - user1410404
1
此外,感谢您的Xml(un)Escape方法,但使用它们意味着需要读取和重新创建整个内部XML。这恰好是我试图避免的。 - user1410404

0

我理解您不想解析和重新创建转义字符的愿望,但除非您完全自定义它,否则我找不到避免这样做的方法。也许这并不是太糟糕?

string TXML = @"<xml><text>hall&#xF6;le</text></xml>";
TXML = TXML.Replace("&", "&amp;");
XmlTextReader r = new XmlTextReader(new StringReader(TXML));
r.Read(); r.Read();

string o = r.ReadOuterXml();
o = o.Replace("&amp;", "&");

是的,也许这是唯一的方法。谢谢你。但除了有一个非常粗糙的解决方案之外,它可能会影响应用程序的性能。我从一个大型XML中读取片段,并且需要多次读写源代码。 - user1410404
同一来源?只需读取一次并将其存储在变量中,然后您可以使用该变量多次写出。 - seekerOfKnowledge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接