【问题标题】:How to remove duplicate attributes from XML with C#如何使用 C# 从 XML 中删除重复的属性
【发布时间】:2011-09-30 09:12:55
【问题描述】:

我正在解析来自第三方提供商的一些 XML 文件,不幸的是它并不总是格式良好的 XML,因为有时某些元素包含重复的属性。

我无法控制来源,我不知道哪些元素可能有重复的属性,也不知道重复的属性名称。

显然,将内容加载到 XMLDocument 对象会在重复属性上引发 XmlException,因此我可以使用 XmlReader 逐个元素地遍历 XML 元素并在到达违规元素。

但是,XmlException 是在 reader.Read() 上引发的 - 在我有机会检查元素的属性之前。

这是一个演示问题的示例方法:

public static void ParseTest()
{
    const string xmlString = 
        @"<?xml version='1.0'?>
        <!-- This is a sample XML document -->
        <Items dupattr=""10"" id=""20"" dupattr=""33"">
            <Item>test with a child element <more/> stuff</Item>
        </Items>";

    var output = new StringBuilder();
    using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
    {
        XmlWriterSettings ws = new XmlWriterSettings();
        ws.Indent = true;
        using (XmlWriter writer = XmlWriter.Create(output, ws))
        {
            while (reader.Read())   /* Exception throw here when Items element encountered */
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Element:
                        writer.WriteStartElement(reader.Name);
                        if (reader.HasAttributes){ /* CopyNonDuplicateAttributes(); */}
                        break;
                    case XmlNodeType.Text:
                        writer.WriteString(reader.Value);
                        break;
                    case XmlNodeType.XmlDeclaration:
                    case XmlNodeType.ProcessingInstruction:
                        writer.WriteProcessingInstruction(reader.Name, reader.Value);
                        break;
                    case XmlNodeType.Comment:
                        writer.WriteComment(reader.Value);
                        break;
                    case XmlNodeType.EndElement:
                        writer.WriteFullEndElement();
                        break;
                }
            }

        }
    }
    string str = output.ToString();
}

是否有另一种方法来解析输入并删除重复的属性,而无需使用正则表达式和字符串操作?

【问题讨论】:

  • 只有在 XML 处理器 API 提供任何允许您挂钩处理并处理错误情况的挂钩时才有可能
  • 有趣的问题,期待看到解决方案!
  • 我想你的问题已经在这里得到了回答:stackoverflow.com/questions/4085065/…
  • 使用 XML 将无法解决此问题,因为您的输入不是 XML。您说您无法控制输入,但您能否至少让您的上级意识到您的供应商没有向您发送 XML?你至少能确保你的vendor知道这一点吗?任何愚蠢到发送这些数据的组织都可能愚蠢到没有意识到它不是 XML。
  • -1:不,这个问题是关于根据属性值删除彼此重复的元素。这个问题是关于具有相同属性的多个副本的“元素”,例如&lt;e a="1" a="2"/&gt;,它不是 XML。

标签: c# xml validation html-agility-pack


【解决方案1】:

我通过将 XML 视为 HTML 文档找到了解决方案。然后使用开源的Html Agility Pack 库,我能够得到有效的XML。

诀窍是先用 HTML 标头保存 xml。
所以替换 XML 声明
&lt;?xml version="1.0" encoding="utf-8" ?&gt;
使用这样的 HTML 声明:
!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;

一旦将内容保存到文件中,此方法将返回一个有效的 XML 文档。

// Requires reference to HtmlAgilityPack
public XmlDocument LoadHtmlAsXml(string url)
{
    var web = new HtmlWeb();

    var m = new MemoryStream();
    var xtw = new XmlTextWriter(m, null);

    // Load the content into the writer
    web.LoadHtmlAsXml(url, xtw);

    // Rewind the memory stream
    m.Position = 0;

    // Create, fill, and return the xml document
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml((new StreamReader(m)).ReadToEnd());
    return xmlDoc;
}

重复的属性节点被自动删除,后面的属性值会覆盖前面的属性值。

【讨论】:

  • 非常感谢!这将为我们的支持团队节省大量手动编辑。
【解决方案2】:

好的认为你需要捕捉错误:

那么你应该可以使用以下方法:

reader.MoveToFirstAttribute();

reader.MoveToNextAttribute()

获取以下属性:

reader.Value
reader.Name

这将使您能够获取所有属性值。

【讨论】:

  • 我可以捕获错误并处理当前节点上的属性(即复制非重复项)但问题是继续处理文档的其余部分,因为reader.Read() 返回 false 所以没有更多元素得到处理。
  • #Catch22,是的,我在尝试恢复代码时确实遇到了这个问题。我希望你能找到解决办法。看看这里:bytes.com/topic/c-sharp/answers/… 看起来 XMLReader 是错误不能容忍的。这通常是个好消息,但在您的情况下,这意味着我建议的解决方案可能不起作用。对不起
猜你喜欢
  • 2023-04-04
  • 2022-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多