如何使用XmlDocument和/或XDocument来解析Windows 1252中编码的数字字符引用?

时间:2009-07-09 21:47:18

标签: .net xml linq-to-xml

我正在处理来自应用程序的XML数据,我们得到这样的XML:

<elt attrib="Swedish: &#228; &#246; Euro: &#128; Quotes: &#145; &#146; &#147; &#148;">
Swedish: &#228; &#246; Euro: &#128; Quotes: &#145; &#146; &#147; &#148;
</elt>

我希望属性值和内部文本值为

Swedish: ä ö Euro: € Quotes: ‘ ’ “ ”

但代码如下:

Dim sXml As String = "<?xml version = ""1.0"" encoding = ""Windows-1252""?>" & vbCrLf & _
  "<elt attrib=""Swedish: &#228; &#246; Euro: &#128; Quotes: &#145; &#146; &#147; &#148;"">" & _
  "Swedish: &#228; &#246; Euro: &#128; Quotes: &#145; &#146; &#147; &#148;" & _
  "</elt>"

Dim X As New XmlDocument
X.LoadXml(sXml)

TextBox1.Text = "Attribute: {" & X.DocumentElement.Attributes("attrib").Value & "}" & _
  vbCrLf & "InnerText: {" & X.DocumentElement.InnerText & "}" & vbCrLf & _
  "Length: " & Convert.ToString(Len(X.DocumentElement.InnerText))

或者这个:

Dim X As XDocument = XDocument.Parse(sXml)

TextBox1.Text = "Attribute: {" & X.Root.Attribute("attrib").Value & "}" & _
  vbCrLf & "InnerText: {" & X.Root.Value & "}" & vbCrLf & _
  "Length: " & Convert.ToString(Len(X.Root.Value))

告诉我:

{Swedish: ä ö Euro:  Quotes:    }

它们的长度都是正确的36,所以显然我想要欧元和引用我得到别的东西,大概是基于Unicode编码。

2 个答案:

答案 0 :(得分:0)

请不要通过String类型操作XML。它经常会弄乱。

您的测试示例未使用真实数据文件,是吗?一定要测试你要用的东西。你不知道测试与现实有何不同。您需要获取其中一个要处理的文件,并使用XDocument.Load读取它。

之后,请逐个查看属性值。


我尝试了以下内容,并且有效:

using (var reader = XmlReader.Create(@"..\..\..\..\Swedish.xml"))
{
    var sw = XDocument.Load(reader);
    var element = sw.Element("elt");
    if (element != null)
    {
        var attribute = element.Attribute("attrib");
        if (attribute != null)
        {
            var v = attribute.Value;
            for (var i=0; i<36; i++)
            {
                var c = v[i];

                Console.WriteLine("v[{0}]={1} \t('{2}')", i,(int) c, c);
            }

            Console.WriteLine();
        }
    }
}

输出结果为:

v[0]=83         ('S')
v[1]=119        ('w')
v[2]=101        ('e')
v[3]=100        ('d')
v[4]=105        ('i')
v[5]=115        ('s')
v[6]=104        ('h')
v[7]=58         (':')
v[8]=32         (' ')
v[9]=228        ('ä')
v[10]=32        (' ')
v[11]=246       ('ö')
v[12]=32        (' ')
v[13]=69        ('E')
v[14]=117       ('u')
v[15]=114       ('r')
v[16]=111       ('o')
v[17]=58        (':')
v[18]=32        (' ')
v[19]=128       ('?')
v[20]=32        (' ')
v[21]=81        ('Q')
v[22]=117       ('u')
v[23]=111       ('o')
v[24]=116       ('t')
v[25]=101       ('e')
v[26]=115       ('s')
v[27]=58        (':')
v[28]=32        (' ')
v[29]=145       ('?')
v[30]=32        (' ')
v[31]=146       ('?')
v[32]=32        (' ')
v[33]=147       ('?')
v[34]=32        (' ')
v[35]=148       ('?')

我认为问号是由我的控制台设置的,但你可以看到数值是正确的。

答案 1 :(得分:0)

首先,无论输入文件的编码是什么,数字字符实体都被解释为相同。 XML严格按照Unicode定义(任何其他编码首先映射到Unicode),数字字符实体代表Unicode代码点。

正因为如此,当您将视为XML 时,您的XML恰好具有使用XmlDocument而不是其他的语义含义。如果你想获得另一个结果,那么你真的试图将它解析为非完全XML。这不是.NET XML API允许你做的事情,甚至不是XmlReader(因为它真的不应该是你可以定制的东西)。

您最接近的是首先将输入“XML”预处理为文本,用正确的Unicode代码点替换这些数字字符实体 - 例如,使用Regex。然而,这可能很棘手,因为对任意输入XML这样做将要求您能够区分不应该发生扩展的位置(例如,在CDATA块内部)。