【问题标题】:Split XML file in different XML files up according to node attributes根据节点属性将 XML 文件拆分为不同的 XML 文件
【发布时间】:2021-01-16 00:27:16
【问题描述】:

我想根据某个节点的不同属性拆分一个 XML 文件,创建单独的 XML 文件,所有这些文件在文件的顶部都具有相同的节点,然后是节点 + 属性及其底层内容,直到该节点的末尾.

所有分离的 XML 文件都需要以相似的结束节点结束。

示例 XML 文件:

<?xml version=""1.0"" encoding=""UTF-8""?>
<node1>
  <node2>
    <node3 attribute='1'>item</node3>
    <node3 attribute='2'>item</node3>
    <node3 attribute='3'>item</node3>
  </node2>
<node6 attribute='1'>
    <node7>item = (node3 attribute2)</node7>
    <node8>item = (node3 attribute3)</node8>
</node6>
<node6 attribute='2'>
    <node9>item = (node3 attribute1)</node9>
    <node10>item = (node3 attribute2)</node10>
</node6>
</node1>

在这个例子中,我想使用 node6 的属性作为创建新 XML 文件的断点。 生成 2 个 XML 文件,如下所示:

分离的 XML 1:

<?xml version=""1.0"" encoding=""UTF-8""?>
<node1>
  <node2>
    <node3 attribute='1'>item</node3>
    <node3 attribute='2'>item</node3>
    <node3 attribute='3'>item</node3>
  </node2>
<node6 attribute='1'>
    <node7>item = (node3 attribute2)</node7>
    <node8>item = (node3 attribute3)</node8>
</node6>

分离的 XML 2:

<?xml version=""1.0"" encoding=""UTF-8""?>
<node1>
  <node2>
    <node3 attribute='1'>item</node3>
    <node3 attribute='2'>item</node3>
    <node3 attribute='3'>item</node3>
  </node2>
<node6 attribute='2'>
    <node9>item = (node3 attribute1)</node9>
    <node10>item = (node3 attribute2)</node10>
</node6>
</node1>

我一直在寻找并处理所有这些答案,但它们并没有帮助我找到上述正确的代码。

https://stackoverflow.com/questions/30374533/split-xml-files-newbie

How to split an xml file in vb

Splitting Xml Document according to node

谁能帮我弄清楚最好的方法是什么?

【问题讨论】:

  • 您熟悉 XSLT 吗?它可以为您完成这项工作,例如参见stackoverflow.com/questions/5578602/…。我也是一名 VB 程序员,但我不建议将这种或任何其他类似的编程语言用于此类任务(除非您的日程安排非常紧张,这迫使您玩肮脏的把戏而不是产生常规的解决方案)。我建议您检查 XSLT 并使用它而不是 VB。它是适合工作的工具,因此您可以事半功倍。
  • 感谢 miroxlav 的信息。不幸的是,我完全不熟悉 XSLT。我的目标是为另一个用户编写一个 Windows 窗体程序,以便能够使用该程序拆分他们的 XML 文件。是否可以在 VB Windows 窗体中实现 XSLT 程序?

标签: xml vb.net


【解决方案1】:

我知道您专门要求提供 VB 解决方案,但这里有一个您可以适应的 C# 解决方案。

using System;
using System.Windows.Forms;
using System.Xml.Linq;
using System.IO;

namespace SplitXmlFile_41385730
{
    public partial class Form1 : Form
    {
        public static string incomingXML = @"M:\StackOverflowQuestionsAndAnswers\SplitXmlFile_41385730\SplitXmlFile_41385730\Samples\data.xml";
        public static string outgoingXML = @"M:\StackOverflowQuestionsAndAnswers\SplitXmlFile_41385730\SplitXmlFile_41385730\Samples\data_out.xml";
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            XElement theincomingDoc = new XElement(XDocument.Load(incomingXML).Root);//the incoming XML

            //store the header of your files
            XElement header = new XElement(theincomingDoc);
            header.Elements("node6").Remove();//remove these nodes since they need to be parked in their own file
            int fileCounter = 0;//hold on, we'll use this in a moment

            //loop through the different nodes you're interested in
            foreach (XElement item in theincomingDoc.Elements("node6"))
            {
                fileCounter++;//increment the file counter
                string outfilename = Path.GetDirectoryName(outgoingXML) + "\\" + Path.GetFileNameWithoutExtension(outgoingXML) + fileCounter + Path.GetExtension(outgoingXML);//come up with a file name that suits your needs
                XDocument newoutfile = new XDocument("", new XElement(header));//create a new document and start it with the header we already stored
                newoutfile.Element("node1").Add(item);//now add the node you need separated
                newoutfile.Save(outfilename, SaveOptions.None);//save the file
            }

        }
    }
}

输入文件是这样的:

<?xml version="1.0"?>
<node1>
  <node2>
    <node3 attribute="1">item</node3>
    <node3 attribute="2">item</node3>
    <node3 attribute="3">item</node3>
  </node2>
<node6 attribute="1">
    <node7>item = (node3 attribute2)</node7>
    <node8>item = (node3 attribute3)</node8>
</node6>
<node6 attribute="2">
    <node9>item = (node3 attribute1)</node9>
    <node10>item = (node3 attribute2)</node10>
</node6>
</node1>

得到了 2 个如下所示的文件: Data_out1.xml

<?xml version="1.0" encoding="utf-8"?>
<node1>
  <node2>
    <node3 attribute="1">item</node3>
    <node3 attribute="2">item</node3>
    <node3 attribute="3">item</node3>
  </node2>
  <node6 attribute="1">
    <node7>item = (node3 attribute2)</node7>
    <node8>item = (node3 attribute3)</node8>
  </node6>
</node1>

data_out2.xml

<?xml version="1.0" encoding="utf-8"?>
<node1>
  <node2>
    <node3 attribute="1">item</node3>
    <node3 attribute="2">item</node3>
    <node3 attribute="3">item</node3>
  </node2>
  <node6 attribute="2">
    <node9>item = (node3 attribute1)</node9>
    <node10>item = (node3 attribute2)</node10>
  </node6>
</node1>

【讨论】:

  • 谢谢大火。我使用您的输入(转换为 VB)以及其他反馈来创建我的答案中提到的工作解决方案。我希望这将有助于未来面临类似挑战的用户。
【解决方案2】:

感谢大家的支持!

使用 Bibek Gautam 的 question and answer 作为大家和其他人的参考和反馈,我想出了以下工作代码(在一个单独的类中)将提到的示例 XML 划分为包含公共字符串和文件特定字符串的单独 XML 文件使用节点 7、8、9 和 10 作为节点 3 属性应该在公共字符串中的参考,从而排除其他节点 3 的可能性。

代码包含示例 XML 中未提及的一些额外节点。

我发布了几乎完整的代码,以便其他有类似目标的人可以参考。

代码:

Shared Sub CreateXML()

    Dim xOrgXml As New XmlDocument
    Dim pSavelocation As String = "mysavelocation"
    Dim pProgressbar As ProgressBar = Form3.f3.ProgressBar1
    Dim cCommonString As String
    Dim dDocumentRootNodes As XmlNodeList
    'implemented progessbar'
    Dim mProgressBarMaximum As Integer         
    Dim mFoldername As String

    Try
        'Public class containing shared location of source XML'
        xOrgXml.Load(ClsSharedProperties.filePath)
        cCommonString = "<?xml version=""1.0""?>" & "<Node1>"
        dDocumentRootNodes = xOrgXml.GetElementsByTagName("Node1")
        mProgressBarMaximum = xOrgXml.GetElementsByTagName("Node6").Count + xOrgXml.GetElementsByTagName("Node3").Count

        pProgressbar.Minimum = 0
        pProgressbar.Maximum = mProgressBarMaximum
        pProgressbar.Value = 0
        pProgressbar.Visible = True

        '==================================================================================================================='
        'Building Common String'   
        '==================================================================================================================='

        For Each Node1Node As XmlNode In dDocumentRootNodes
            Dim Node1ChildNodes As XmlNodeList = Node1Node.ChildNodes

            For Each Node1Childnode As XmlNode In Node1ChildNodes
                If Node1Childnode.Name = "node4" Then
                    cCommonString = cCommonString & Node1Childnode.OuterXml

                Else
                    If Node1Childnode.Name = "node5" Then
                        cCommonString = cCommonString & Node1Childnode.OuterXml

                    Else
                        If Node1Childnode.Name = "node12" Then
                            cCommonString = cCommonString & Node1Childnode.OuterXml
                        End If
                    End If
                End If
            Next
        Next

        Dim mXMLDocSave As XmlDocument
        Dim mFileName As String
        Dim fFullString As String

        mXMLDocSave = New XmlDocument()

        '=============================================================='
        'Creating Directories and files For xml Getting Name and attribute value from Node6-NODE1node'
        '==============================================================='

        For Each Node1Node As XmlNode In dDocumentRootNodes
            Dim Node1ChildNodes As XmlNodeList = Node1Node.ChildNodes
            For Each NODE1node As XmlNode In Node1ChildNodes
                
                If NODE1node.Name = "Node6" Then

                    Dim Node6Attribute As XmlAttributeCollection = NODE1node.Attributes
                    If Node6Attribute.GetNamedItem("attribute").Value = "1" Then
                        pProgressbar.Increment(1)
                        Dim cCommonStringNode6_1 As String = cCommonString

                        Dim i As Integer
                        Dim s As String

                        For i = 0 To (Form3.f3.CheckedListBox1.Items.Count - 1)
                            If Form3.f3.CheckedListBox1.GetItemChecked(i) = True Then
                                s = Form3.f3.CheckedListBox1.Items(i).ToString
                                If s = "EXAMPLE A" Then
                                    mFoldername = "EXAMPLE A"
                                    If (Not IO.Directory.Exists(pSavelocation & "\" & mFoldername)) Then
                                        IO.Directory.CreateDirectory(pSavelocation & "\" & mFoldername)
                                    End If
                                ElseIf s = "EXAMPLE B" Then
                                    mFoldername = "EXAMPLE B"
                                    If (Not IO.Directory.Exists(pSavelocation & "\" & mFoldername)) Then
                                        IO.Directory.CreateDirectory(pSavelocation & "\" & mFoldername)
                                    End If
                                End If
                            End If
                        Next
                        For i = 0 To (Form3.f3.CheckedListBox1.Items.Count - 1)
                            If Form3.f3.CheckedListBox1.GetItemChecked(i) = True Then
                                s = Form3.f3.CheckedListBox1.Items(i).ToString
                                If s = "EXAMPLE A" Then
                                    mFileName = Date.Now.ToString("yyyyMMdd-HHmm") + "_" + NODE1node.Name.ToString + "_" + (Node6Attribute.GetNamedItem("attribute").Value).ToString + "_" + "EXAMPLE A"
                                    mFileName = mFileName.Replace(".", "_").Replace(" ", "_").Replace("''", "_").Replace("<", "").Replace(">", "").Replace("d", "D")
                                ElseIf s = "EXAMPLE B" Then
                                    mFileName = Date.Now.ToString("yyyyMMdd-HHmm") + "_" + NODE1node.Name.ToString + "_" + (Node6Attribute.GetNamedItem("attribute").Value).ToString + "_" + "EXAMPLE B"
                                    mFileName = mFileName.Replace(".", "_").Replace(" ", "_").Replace("''", "_").Replace("<", "").Replace(">", "").Replace("d", "D")

                                End If
                            End If
                        Next
                        For Each Node1Node2 As XmlNode In dDocumentRootNodes
                            Dim Node1ChildNodes2 As XmlNodeList = Node1Node2.ChildNodes
                            For Each NODE1node2 As XmlNode In Node1ChildNodes2

                                If NODE1node2.Name = "Node3" Then
                                    pProgressbar.Increment(1)
                                    Dim xNode6Node3List As XmlNodeList = xOrgXml.SelectNodes("/Node1/Node6[@attribute='1']//Node3")

                                    For Each Node6NODE3_Name As XmlNode In xNode6Node3List
                                        pProgressbar.Increment(1)
                                        If (Node6NODE3_Name.InnerText).ToString = (NODE1node2.Attributes("attribute").Value).ToString Then

                                            Dim NODE1_NODE3_Node_String As String = NODE1node2.OuterXml.ToString
                                            'check if node specific string already contains the selected node. If not add it else skip it'
                                            If cCommonStringNode6_1.Contains(NODE1_NODE3_Node_String) = False Then
                                                cCommonStringNode6_1 = cCommonStringNode6_1 & NODE1node2.OuterXml
                                            End If
                                        End If
                                    Next
                                End If
                            Next
                        Next
                        'create the fullstring to be saved as new XML document'
                        fFullString = cCommonStringNode6_1 & NODE1node.OuterXml & "</Node1>"
                        mXMLDocSave.LoadXml(fFullString)
                        'Make all node6 attributes have value "1"'
                        For Each node2 As XmlAttribute In mXMLDocSave.SelectNodes("//Node6/@attribute")
                            node2.Value = "1"
                        Next
                        Dim countervalue As Integer = 0
                        For Each Node1Childnode As XmlNode In mXMLDocSave.SelectNodes("/Node1/Node3")
                            If Node1Childnode.Name = "Node3" Then

                                Dim NODE3_NodeList As XmlNodeList = Node1Childnode.ChildNodes
                                For Each NODE3_Node As XmlNode In NODE3_NodeList

                                    If NODE3_Node.Name = "Node11" Then
                                        countervalue += 1
                                        NODE3_Node.InnerText = countervalue.ToString
                                    End If
                                Next
                            End If
                        Next
                        mXMLDocSave.Save(pSavelocation & "\" & mFoldername & "\" & mFileName & ".xml")
                        mXMLDocSave = New XmlDocument()
                        fFullString = String.Empty
                        mFoldername = String.Empty
                        mFileName = String.Empty
                        End If
                End If
            Next
        Next
    Catch ex As Exception
        MessageBox.Show(ex.Message & vbCrLf & "Stack Trace: " & vbCrLf & ex.StackTrace)
    End Try

【讨论】:

    猜你喜欢
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-18
    • 1970-01-01
    • 2020-08-07
    相关资源
    最近更新 更多