【问题标题】:Find and Replace through XML files通过 XML 文件查找和替换
【发布时间】:2015-02-26 22:44:06
【问题描述】:

我有很多 XML 文件需要编辑。 我需要找到所有实例: 示例

<Btn> 
    <sText>Hold</sText>

并在其前添加一个字段

  <Btn>//star of new fields
      <sText>Tools</sText>    
      *rest of fields*     
  </Btn> //end of added fields  
  <Btn> //start of original search
      <sText>Hold</sText>

我已经阅读过在 XML 上使用正则表达式是不可取的。对于这样的事情,实现多个文件的大型一次性操作的最佳方法是什么?

我尝试了正则表达式,但没有运气,只是开始搜索所需的字段。

/<Btn>(.*?(\n))+.*?<sText>Hold</sText>/im

目前使用notepad++、括号等编辑器来编辑文件。任何有关进行大型一次性操作的建议将不胜感激。在 GUI 中手动更改数百个配置是不可取的。只是寻找另一种方法来节省理智。

【问题讨论】:

  • I have read the using regex on XML is not advisable 好吗?所以编写一个使用 xml 解析器的脚本,然后在必要的文件上运行该脚本。
  • 在 BAT 文件中执行此操作可能不是一个好的选择。你知道任何其他语言,例如C#?如果是这样,请添加您喜欢的语言并删除 batch-file 标记。
  • 查看 UNIX/LINUX 工具,如 VIM 和 SED 进行此类操作。它们具有更强大的正则表达式功能。
  • @PieterGeerkens:想法是根本不使用正则表达式来解析 XML
  • @JohnSaunders:作为一个在我的职业生涯中推出了近 20 个 DSL 解析器的人,实现了从递归下降到 LEX/YACC 语法的任何东西,我可以说我偶尔也会使用 REGEX,因为完整的解析器将使用大锤打苍蝇。关键在于使用正确的工具来完成您面前的工作。

标签: c# regex xml


【解决方案1】:

您可以为您的 XML 文档创建一个对象。从那里您可以遍历其所有节点,找到您要查找的内容并将它们添加到列表中。当您已经拥有列表时,您可以编写用于插入所需节点的逻辑。我正在使用 LINQ。

public class Program
{
    static void Main(string[] args)
    {
        XDocument doc = XDocument.Load("YourXmlFile.xml");

        RootElement root = new RootElement(doc.Elements().FirstOrDefault());

        foreach (XElement item in root.GetInstances())
        {
            //--Your logic for adding the fields you want
        }

        Console.ReadLine();
    }
}

public class RootElement
{
    public List<XElement> childElements { get; set; }

    public RootElement(XElement xElement)
    {
        childElements = new List<XElement>();

        foreach (XElement e in xElement.Elements())
        {
            childElements.Add(e);
        }
    }

    public List<XElement> GetInstances()
    {
        List<XElement> instances = new List<XElement>();
        foreach (XElement item in childElements)
        {
            if (item.Name == "Btn")
            {
                IEnumerable<XElement> elements = item.Elements();
                XElement child = elements.FirstOrDefault(x => x.Name == "sText");

                if (child != null)
                {
                    if (child.Value == "Hold")
                    {
                        instances.Add(item);
                    }
                }
            }
        }

        return instances;
    }
}

【讨论】:

    【解决方案2】:

    我有一个 XSL 方法,您可能想尝试一下。 XSL 非常适合将一种 XML 文档转换为另一种(除其他外)。

    据我了解,您需要找到 Btn 的每个实例并将其复制到其当前位置之前的新实例。

    考虑到这一点,这就是我的工作方式。

    Test.xml 文件:

    <?xml version="1.0" encoding="utf-8"?>
    <?xml-stylesheet type="text/xsl" href="Test.xslt"?>
    
    <Something>
      <Btn>
        <sText>Hold</sText>
        <Another>Foo</Another>
      </Btn>
      <Btn>
        <sText>Hold</sText>
      </Btn>
      <Btn>
        <sText>Hold</sText>
      </Btn>
    </Something>
    

    注意样式表引用的使用,您需要将其添加到您要编辑的文档中。

    Test.xslt 文件:

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
      <xsl:output method="xml" indent="yes"/>
    
      <xsl:template match="/">
        <xsl:element name="Output">
          <xsl:apply-templates select="//Btn" />
        </xsl:element>
      </xsl:template>
    
      <xsl:template match="Btn">
        <xsl:element name="NewBtn">
          <xsl:copy-of select="current()/*" />
        </xsl:element>
        <xsl:element name="Btn">
          <xsl:copy-of select="current()/*" />
        </xsl:element>
      </xsl:template>
    
    </xsl:stylesheet>
    

    输出应如下所示:

    <?xml version="1.0" encoding="utf-8"?>
    <Output>
      <NewBtn>
        <sText>Hold</sText>
        <Another>Foo</Another>
      </NewBtn>
      <Btn>
        <sText>Hold</sText>
        <Another>Foo</Another>
      </Btn>
      <NewBtn>
        <sText>Hold</sText>
      </NewBtn>
      <Btn>
        <sText>Hold</sText>
      </Btn>
      <NewBtn>
        <sText>Hold</sText>
      </NewBtn>
      <Btn>
        <sText>Hold</sText>
      </Btn>
    </Output>
    

    在本例中,新复制的 Btn 节点实例被命名为 NewBtn。

    请注意,我在此处更改/添加了一些元素(输出、某些东西)以获取有效的 XML。

    希望对你有帮助!

    【讨论】:

      【解决方案3】:

      您可以尝试不使用正则表达式来解决它。例如你可以使用XmlReaderXmlWriter

      • 使用 XmlReader 读取一行
      • 检查您的情况
      • 跳过/修改行
      • 用 XmlWriter 写行

      这是最节省内存和 CPU 的解决方案,因为您不需要将整个文件加载到内存中,并且与 XDocument 或其他花哨的 xml 解析器相比,C# 中的 XML Writer/Reader 非常快。此外,它很简单,因此您需要处理正则表达式,并且可以包含您需要的任何复杂逻辑。

      【讨论】:

      • XmlReader/XmlWriter 是最难使用的 XML API,因为它们是最低级别。
      猜你喜欢
      • 2014-08-17
      • 1970-01-01
      • 2021-11-06
      • 2019-10-16
      • 2017-08-07
      • 1970-01-01
      • 1970-01-01
      • 2010-10-06
      相关资源
      最近更新 更多