【问题标题】:How to Split an XML file into multiple XML Files based on nodes如何根据节点将一个 XML 文件拆分为多个 XML 文件
【发布时间】:2013-01-22 09:49:31
【问题描述】:

我有一个如下的 XML 文件

<?xml version="1.0>
<EMR>
  <CustomTextBox>
    <Text>WNL</Text>
    <Type>TextBox</Type>
    <Width>500</Width>
    <id>txt1</id>
  </CustomTextBox>

  <CustomTextBox>
    <Text>WNL</Text>
    <Type>TextBox</Type>
    <Width>500</Width>
    <id>txt2</id>
  </CustomTextBox>

  <AllControlsCount>
    <Width>0</Width>
    <id>ControlsID</id>
  </AllControlsCount>
</EMR>

我想将 xml 文件分成三份。根据其节点

文件 1:

<?xml version="1.0>
<CustomTextBox>
  <Text>WNL</Text>
  <Type>TextBox</Type>
  <Width>500</Width>
  <id>txt1</id>
</CustomTextBox>

文件 2:

<?xml version="1.0>
<CustomTextBox>
  <Text>WNL</Text>
  <Type>TextBox</Type>
  <Width>500</Width>
  <id>txt2</id>
</CustomTextBox>

文件 3:

<?xml version="1.0>
<AllControlsCount>
  <Width>0</Width>
  <id>ControlsID</id>
</AllControlsCount>

节点也是动态的,它们可能会发生变化。如何根据节点将此 xml 文件拆分为多个。如果有人知道,请分享。

【问题讨论】:

  • 您是否要求我们“编写”您的自定义逻辑以创建新的 XML 文件?您可以使用 XmlDocument 类创建一个 XPathExpression 并将所有内部 XML 写入新的 XML 文件。
  • 我只有一个动态创建的 xml 文件(如上一个),其中包含差异控件作为节点。我只想通过控制(节点)来分割它。
  • 所以你要我们写你的代码?请努力为自己找到解决方案(在这里很容易),并仅发布您遇到的具体问题。
  • @Nithesh 所以基本上没有基于名称的逻辑,但您只想为每个 2 级节点(根节点的直接子节点)创建一个单独的 XML 文件?

标签: c# xml split


【解决方案1】:

试试 LinqToXml

var xDoc = XDocument.Parse(Resource1.XMLFile1); // loading source xml
var xmls = xDoc.Root.Elements().ToArray(); // split into elements

for(int i = 0;i< xmls.Length;i++)
{
    // write each element into different file
    using (var file = File.CreateText(string.Format("xml{0}.xml", i + 1)))
    {
        file.Write(xmls[i].ToString());
    }
}

它将获取根元素内定义的所有元素并将其内容写入单独的文件。

【讨论】:

    【解决方案2】:

    使用 Linq to Xml 更简单 - 您可以使用 XElement.Save 方法将任何元素保存到单独的 xml 文件中:

    XDocument xdoc = XDocument.Load(path_to_xml);
    int index = 0;
    foreach (var element in xdoc.Root.Elements())
        element.Save(++index + ".xml");
    

    或者一行

    XDocument.Load(path_to_xml).Root.Elements()
             .Select((e, i) => new { Element = e, File = ++i + ".xml" })
             .ToList().ForEach(x => x.Element.Save(x.File));
    

    【讨论】:

      【解决方案3】:

      您可以使用 XmlTextReaderXmlWriter 类来完成您想要的。但是您需要知道从哪里开始创建新的 XML 文件。查看您的示例,您希望拆分根节点中包含的每个节点。

      这意味着一旦你开始阅读 XML 文件,你需要确保你在根节点内,然后你需要跟随你对 XML 的深入了解,这样你就可以在到达根节点中的下一个节点时关闭文件。

      例如看这个 - 我从 file.xml 读取 XML 并打开 XML 编写器。当我到达根节点中包含的第一个节点时,我开始编写元素。

      我记得变量“treeDepth”中的深度,它代表了XML树结构的深度。

      基于当前读取的节点,我做了一个动作。 当我到达树深度为 1 的 End 元素时,这意味着我又回到了根节点,所以我关闭了当前的 XML 文件并打开了新的。

      XmlTextReader reader = new XmlTextReader ("file.xml");
      
      XmlWriter writer = XmlWriter.Create("first_file.xml")
      writer.WriteStartDocument();
      
      int treeDepth = 0;
      
      while (reader.Read()) 
      {
          switch (reader.NodeType) 
          {
              case XmlNodeType.Element:
      
                  //
                  // Move to parsing or skip the root node
                  //
      
                  if (treeDepth > 0)
                      writer.WriteStartElement(reader.Name);
      
                  treeDepth++;
      
      
                  break;
        case XmlNodeType.Text:
      
                  //
                  // Write text here
                  //
      
                  writer.WriteElementString (reader.Value);
      
                  break;
        case XmlNodeType.EndElement:
      
                  //
                  // Close the end element, open new file
                  //
      
                  if (treeDepth == 1)
                  {
                      writer.WriteEndDocument();
                      writer = new XmlWriter("file2.xml");
                      writer.WriteStartDocument();
                  }
      
                  treeDepth--;
      
                  break;
          }
      }
      
      writer.WriteEndDocument();
      

      请注意,此代码并不能完全解决您的问题,而只是解释了完全解决问题所需的逻辑。

      有关 XML 阅读器和编写器的更多帮助,请阅读以下链接:

      http://support.microsoft.com/kb/307548

      http://www.dotnetperls.com/xmlwriter

      【讨论】:

        【解决方案4】:

        我采用了 Legoless 的答案并将其扩展为适合我的版本,因此我分享它。出于我的需要,我需要拆分每个文件的多个条目,而不仅仅是原始问题中显示的每个文件的单个条目,这意味着我需要保留更高级别的元素以确保生成的 xml 有效文件。

        因此,您需要提供要拆分的级别以及所需的每个文件的条目数。

        public class XMLFileManager
        {        
        
            public List<string> SplitXMLFile(string fileName, int startingLevel, int numEntriesPerFile)
            {
                List<string> resultingFilesList = new List<string>();
        
                XmlReaderSettings readerSettings = new XmlReaderSettings();
                readerSettings.DtdProcessing = DtdProcessing.Parse;
                XmlReader reader = XmlReader.Create(fileName, readerSettings);
        
                XmlWriter writer = null;
                int fileNum = 1;
                int entryNum = 0;
                bool writerIsOpen = false;
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;
                settings.NewLineOnAttributes = true;
        
                Dictionary<int, XmlNodeItem> higherLevelNodes = new Dictionary<int, XmlNodeItem>();
                int hlnCount = 0;
        
                string fileIncrementedName = GetIncrementedFileName(fileName, fileNum);
                resultingFilesList.Add(fileIncrementedName);
                writer = XmlWriter.Create(fileIncrementedName, settings);
                writerIsOpen = true;
                writer.WriteStartDocument();
        
                int treeDepth = 0;
        
                while (reader.Read())
                {
                    switch (reader.NodeType)
                    {
                        case XmlNodeType.Element:                        
        
                            treeDepth++;
        
                            if (treeDepth == startingLevel)
                            {
                                entryNum++;
                                if (entryNum == 1)
                                {                                
                                    if (fileNum > 1)
                                    {
                                        fileIncrementedName = GetIncrementedFileName(fileName, fileNum);
                                        resultingFilesList.Add(fileIncrementedName);
                                        writer = XmlWriter.Create(fileIncrementedName, settings);
                                        writerIsOpen = true;
                                        writer.WriteStartDocument();
                                        for (int d = 1; d <= higherLevelNodes.Count; d++)
                                        {
                                            XmlNodeItem xni = higherLevelNodes[d];
                                            switch (xni.XmlNodeType)
                                            {
                                                case XmlNodeType.Element:
                                                    writer.WriteStartElement(xni.NodeValue);
                                                    break;
                                                case XmlNodeType.Text:
                                                    writer.WriteString(xni.NodeValue);
                                                    break;
                                                case XmlNodeType.CDATA:
                                                    writer.WriteCData(xni.NodeValue);
                                                    break;
                                                case XmlNodeType.Comment:
                                                    writer.WriteComment(xni.NodeValue);
                                                    break;
                                                case XmlNodeType.EndElement:
                                                    writer.WriteEndElement();
                                                    break;
                                            }
                                        }
                                    }
                                }
                            }
        
                            if (writerIsOpen)
                            {
                                writer.WriteStartElement(reader.Name);
                            }
        
                            if (treeDepth < startingLevel)
                            {
                                hlnCount++;
                                XmlNodeItem xni = new XmlNodeItem();
                                xni.XmlNodeType = XmlNodeType.Element;
                                xni.NodeValue = reader.Name;
                                higherLevelNodes.Add(hlnCount, xni);
                            }
        
                            break;
                        case XmlNodeType.Text:
        
                            if (writerIsOpen)
                            {
                                writer.WriteString(reader.Value);
                            }
        
                            if (treeDepth < startingLevel)
                            {
                                hlnCount++;
                                XmlNodeItem xni = new XmlNodeItem();
                                xni.XmlNodeType = XmlNodeType.Text;
                                xni.NodeValue = reader.Value;
                                higherLevelNodes.Add(hlnCount, xni);
                            }
        
                            break;
                        case XmlNodeType.CDATA:
        
                            if (writerIsOpen)
                            {
                                writer.WriteCData(reader.Value);
                            }
        
                            if (treeDepth < startingLevel)
                            {
                                hlnCount++;
                                XmlNodeItem xni = new XmlNodeItem();
                                xni.XmlNodeType = XmlNodeType.CDATA;
                                xni.NodeValue = reader.Value;
                                higherLevelNodes.Add(hlnCount, xni);
                            }
        
                            break;
                        case XmlNodeType.Comment:
        
                            if (writerIsOpen)
                            {
                                writer.WriteComment(reader.Value);
                            }
        
                            if (treeDepth < startingLevel)
                            {
                                hlnCount++;
                                XmlNodeItem xni = new XmlNodeItem();
                                xni.XmlNodeType = XmlNodeType.Comment;
                                xni.NodeValue = reader.Value;
                                higherLevelNodes.Add(hlnCount, xni);
                            }
        
                            break;
                        case XmlNodeType.EndElement:
        
                            if (entryNum == numEntriesPerFile && treeDepth == startingLevel || treeDepth==1)
                            {
                                if (writerIsOpen)
                                {
                                    fileNum++;
                                    writer.WriteEndDocument();
                                    writer.Close();
                                    writerIsOpen = false;
                                    entryNum = 0;
                                }                            
                            }
                            else
                            {
                                if (writerIsOpen)
                                {
                                    writer.WriteEndElement();
                                }
        
                                if (treeDepth < startingLevel)
                                {
                                    hlnCount++;
                                    XmlNodeItem xni = new XmlNodeItem();
                                    xni.XmlNodeType = XmlNodeType.EndElement;
                                    xni.NodeValue = string.Empty;
                                    higherLevelNodes.Add(hlnCount, xni);
                                }
                            }
        
                            treeDepth--;
        
                            break;
                    }
                }
        
                return resultingFilesList;
            }
        
            private string GetIncrementedFileName(string fileName, int fileNum)
            {
                return fileName.Replace(".xml", "") + "_" + fileNum + "_" + ".xml";
            }
        }
        
        public class XmlNodeItem
        {        
            public XmlNodeType XmlNodeType { get; set; }
            public string NodeValue { get; set; }
        }
        

        示例用法:

        int startingLevel = 2; //EMR is level 1, while the entries of CustomTextBox and AllControlsCount 
                               //are at Level 2. The question wants to split on those Level 2 items 
                               //and so this parameter is set to 2.
        int numEntriesPerFile = 1;  //Question wants 1 entry per file which will result in 3 files,  
                                    //each with one entry.
        
        XMLFileManager xmlFileManager = new XMLFileManager();
        List<string> resultingFilesList = xmlFileManager.SplitXMLFile("before_split.xml", startingLevel, numEntriesPerFile);
        

        针对问题中的 XML 文件使用时的结果:

        文件 1:

        <?xml version="1.0" encoding="utf-8"?>
        <EMR>
          <CustomTextBox>
            <Text>WNL</Text>
            <Type>TextBox</Type>
            <Width>500</Width>
            <id>txt1</id>
          </CustomTextBox>
        </EMR>
        

        文件 2:

        <?xml version="1.0" encoding="utf-8"?>
        <EMR>
          <CustomTextBox>
            <Text>WNL</Text>
            <Type>TextBox</Type>
            <Width>500</Width>
            <id>txt2</id>
          </CustomTextBox>
        </EMR>
        

        文件 3:

        <?xml version="1.0" encoding="utf-8"?>
        <EMR>
          <AllControlsCount>
            <Width>0</Width>
            <id>ControlsID</id>
          </AllControlsCount>
        </EMR>
        

        另一个层次更深的例子,每个文件显示多个条目:

        int startingLevel = 4; //splitting on the 4th level down which is <ITEM>
        int numEntriesPerFile = 2;//2 enteries per file. If instead you used 3, then the result 
                                  //would be 3 entries in the first file and 1 entry in the second file.
        
        XMLFileManager xmlFileManager = new XMLFileManager();
        List<string> resultingFilesList = xmlFileManager.SplitXMLFile("another_example.xml", startingLevel, numEntriesPerFile);
        

        原始文件:

        <?xml version="1.0" encoding="utf-8"?>
        <TOP_LEVEL>
          <RESPONSE>
            <DATETIME>2019-04-03T21:39:40Z</DATETIME>  
            <ITEM_LIST>
              <ITEM>
                <ID>1</ID>
                <ABC>Some Text 1</ABC>        
                <TESTDATA><![CDATA[Here is some c data]]></TESTDATA>        
                <A_DATETIME>2019-04-01T01:00:00Z</A_DATETIME>        
                <A_DEEPER_LIST>
                  <DEEPER_LIST_ITEM>
                    <DLID>42</DLID>            
                    <TYPE>Example</TYPE>            
                    <IS_ENABLED>1</IS_ENABLED>            
                  </DEEPER_LIST_ITEM>
                </A_DEEPER_LIST>
              </ITEM>      
              <ITEM>
                <ID>2</ID>
                <ABC>Some Text 2</ABC>        
                <TESTDATA><![CDATA[Here is some c data]]></TESTDATA>        
                <A_DATETIME>2019-04-01T01:00:00Z</A_DATETIME>        
                <A_DEEPER_LIST>
                  <DEEPER_LIST_ITEM>
                    <DLID>53</DLID>            
                    <TYPE>Example</TYPE>            
                    <IS_ENABLED>1</IS_ENABLED>            
                  </DEEPER_LIST_ITEM>
                </A_DEEPER_LIST>
              </ITEM>
              <ITEM>
                <ID>3</ID>
                <ABC>Some Text 3</ABC>        
                <TESTDATA><![CDATA[Here is some c data]]></TESTDATA>        
                <A_DATETIME>2019-04-01T01:00:00Z</A_DATETIME>        
                <A_DEEPER_LIST>
                  <DEEPER_LIST_ITEM>
                    <DLID>1128</DLID>            
                    <TYPE>Example</TYPE>            
                    <IS_ENABLED>1</IS_ENABLED>            
                  </DEEPER_LIST_ITEM>
                </A_DEEPER_LIST>
              </ITEM>
              <ITEM>
                <ID>4</ID>
                <ABC>Some Text 4</ABC>        
                <TESTDATA><![CDATA[Here is some c data]]></TESTDATA>        
                <A_DATETIME>2019-04-01T01:00:00Z</A_DATETIME>        
                <A_DEEPER_LIST>
                  <DEEPER_LIST_ITEM>
                    <DLID>1955</DLID>            
                    <TYPE>Example</TYPE>            
                    <IS_ENABLED>1</IS_ENABLED>            
                  </DEEPER_LIST_ITEM>
                </A_DEEPER_LIST>
              </ITEM>
            </ITEM_LIST>
          </RESPONSE>
        </TOP_LEVEL>
        

        结果文件:

        第一个文件:

        <?xml version="1.0" encoding="utf-8"?>
        <TOP_LEVEL>
          <RESPONSE>
            <DATETIME>2019-04-03T21:39:40Z</DATETIME>
            <ITEM_LIST>
              <ITEM>
                <ID>1</ID>
                <ABC>Some Text 1</ABC>
                <TESTDATA><![CDATA[Here is some c data]]></TESTDATA>
                <A_DATETIME>2019-04-01T01:00:00Z</A_DATETIME>
                <A_DEEPER_LIST>
                  <DEEPER_LIST_ITEM>
                    <DLID>42</DLID>
                    <TYPE>Example</TYPE>
                    <IS_ENABLED>1</IS_ENABLED>
                  </DEEPER_LIST_ITEM>
                </A_DEEPER_LIST>
              </ITEM>
              <ITEM>
                <ID>2</ID>
                <ABC>Some Text 2</ABC>
                <TESTDATA><![CDATA[Here is some c data]]></TESTDATA>
                <A_DATETIME>2019-04-01T01:00:00Z</A_DATETIME>
                <A_DEEPER_LIST>
                  <DEEPER_LIST_ITEM>
                    <DLID>53</DLID>
                    <TYPE>Example</TYPE>
                    <IS_ENABLED>1</IS_ENABLED>
                  </DEEPER_LIST_ITEM>
                </A_DEEPER_LIST>
              </ITEM>
            </ITEM_LIST>
          </RESPONSE>
        </TOP_LEVEL>
        

        第二个文件:

        <?xml version="1.0" encoding="utf-8"?>
        <TOP_LEVEL>
          <RESPONSE>
            <DATETIME>2019-04-03T21:39:40Z</DATETIME>
            <ITEM_LIST>
              <ITEM>
                <ID>3</ID>
                <ABC>Some Text 3</ABC>
                <TESTDATA><![CDATA[Here is some c data]]></TESTDATA>
                <A_DATETIME>2019-04-01T01:00:00Z</A_DATETIME>
                <A_DEEPER_LIST>
                  <DEEPER_LIST_ITEM>
                    <DLID>1128</DLID>
                    <TYPE>Example</TYPE>
                    <IS_ENABLED>1</IS_ENABLED>
                  </DEEPER_LIST_ITEM>
                </A_DEEPER_LIST>
              </ITEM>
              <ITEM>
                <ID>4</ID>
                <ABC>Some Text 4</ABC>
                <TESTDATA><![CDATA[Here is some c data]]></TESTDATA>
                <A_DATETIME>2019-04-01T01:00:00Z</A_DATETIME>
                <A_DEEPER_LIST>
                  <DEEPER_LIST_ITEM>
                    <DLID>1955</DLID>
                    <TYPE>Example</TYPE>
                    <IS_ENABLED>1</IS_ENABLED>
                  </DEEPER_LIST_ITEM>
                </A_DEEPER_LIST>
              </ITEM>
            </ITEM_LIST>
          </RESPONSE>
        </TOP_LEVEL>
        

        【讨论】:

          猜你喜欢
          • 2017-03-14
          • 1970-01-01
          • 1970-01-01
          • 2011-09-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多