XElement .Value吞下嵌入式XML

时间:2014-08-12 15:53:46

标签: c# xml linq xml-parsing

我的问题: 我正在将一堆基于XML的日志(我几乎无法控制)解析为MySQL语句,以便从基于XML的数据库切换到MySQL。这一点让我难过。

如果我查看包含我感兴趣的字符串的IEnumerable<XElement>,我可以看到嵌入式XML语句。但是,如果我获取该字符串的值,则XML语句将消失。 EG:

IEnumerable(<PowerFail />可见):

<StepDetails>Set input voltage to 2.80V WDT should allow CPU power.  CPU should detect PowerFail signal and output a<PowerFail /> tag to the serial line.  WDT should reset every 1.6 seconds</StepDetails>

取值后,字符串中缺少<PowerFail />标记:

Set input voltage to 2.80V WDT should allow CPU power.  CPU should detect PowerFail signal and output a tag to the serial line.  WDT should reset every 1.6 seconds

如果我做.ToString()

,我会得到同样的结果

步骤: 如果您将以下内容粘贴到LinqPad作为C#语句,您可以看到我的意思。 XML标记<PowerFail />消失了。 我注意到它也会在这里消失,除非我在它周围留下滴答声。我已经包含了LinqPad标签,因为我正在解析这些文件(有数万个日志文件可以追溯到几年前)使用一系列LinqPad脚本将日志处理成MySQL并插入它们以创建新数据库。

我的问题: 我意识到我可以用一些正则表达式或子串或其他东西来获取字符串,但似乎我应该能够得到整个字符串,标签和&amp;全部来自IEnumerable,但怎么办呢?此外,我很想知道为什么标签被吞下来只是为了我的启发。

我有大约三十种这类日志异常的变种影响了成千上万的日志(我昨天修复的最后一个日志仅应用于1500多个日志),大约七年左右的数据,所以我想找到一个(更多)通用解决方案,而不是XML标签特定的正则表达式,子字符串或其他每个。我无法更改日志,我不想在传输到新数据库时丢失数据。

第一手查看问题: 剪切&amp;粘贴到LinqPAD作为C#语句(是否有类似JSFiddle for JavaScript的在线方式)?我已经在底部添加了一个正则表达式解决方案,以防有人来寻找类似的东西,但我仍然对更好的方法感兴趣。

string xml = @"<StepResults>
<TestStep Name='2.8V OPERATION' Result='Pass'>
    <OperatorComment/>
    <StepDetails>Set input voltage to 2.80V WDT should allow CPU power.  CPU should detect PowerFail signal and output a<PowerFail/> tag to the serial line.  WDT should reset every 1.6 seconds</StepDetails>
    <Measurements NumberOfMeasurements='1'>
        <Measurement Name='BATTERY VOLTAGE: VOLTS'>
            <MeasuredValue>2.794608</MeasuredValue>
            <Min>2.785000</Min>
            <Max>2.800000</Max>
        </Measurement>
    </Measurements>
</TestStep>
</StepResults>";
var xd = XDocument.Parse(xml);
Console.WriteLine(xd);

var xe = 
    from e in xd.Descendants("StepDetails")
    select e;
Console.WriteLine(xe);
Console.WriteLine(xe.First().Value);

//new code below to show a working regex solution:

string stepDetail = xe.First().ToString();
Regex matchFrontTag = new Regex("^<[^>]*>");
Regex matchRearTag = new Regex("<[^>]*>$");

stepDetail = matchFrontTag.Replace(stepDetail,string.Empty);
stepDetail = matchRearTag.Replace(stepDetail,string.Empty);

Console.WriteLine(stepDetail);

1 个答案:

答案 0 :(得分:1)

正如MSDN documentation for XElement.Value所说:

  

获取或设置此元素的连接文本内容。

所以XElement.Value确实只会返回文本节点,并且(在混合内容的情况下)会忽略非文本节点(但不包含其中包含的文本节点)。

您正在寻找XElement的内部XML,您可以使用XmlReader获取它。

// this writes only the (concatenated) text nodes
Console.WriteLine(xe.First().Value);

// this writes the inner XML, including elements
var reader = xe.First().CreateReader();
reader.MoveToContent();
Console.WriteLine(reader.ReadInnerXml());

如果你更喜欢留在LINQ中,你可以简单地加入所有子节点的字符串表示:

Console.WriteLine(
  xe.First().Nodes().Aggregate("", (result, node) => result += node.ToString())
);

或者

string.Join("", xe.First().Nodes().Select(n => n.ToString())).Dump();

但正如相关问题所说:这些比使用阅读器慢得多。