2016-12-29 90 views
1

我想根據某個節點的不同屬性拆分一個XML文件,創建單獨的XML文件,所有文件都在文件頂部有相同的節點,然後是節點+屬性及其基礎內容,直到此節點結束。根據節點屬性將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

有人可以幫我找出什麼做的最好的方式,這是?

+0

你熟悉XSLT?它可以爲你做這項工作,例如見http://stackoverflow.com/questions/5578602/how-to-filter-nodes-in-xml-using-xslt。我也是一名VB程序員,但我不會推薦使用這種或任何其他類似的編程語言來完成這種類型的任務(除非你有非常緊湊的時間表,這迫使你玩弄骯髒的技巧,而不是生產常規解決方案)。我建議你檢查XSLT並使用它來代替VB。這是適合工作的工具,所以你可以用較少的努力獲得結果。 – miroxlav

+0

感謝信息miroxlav。我很遺憾完全不熟悉XSLT。我的目標是爲其他用戶編寫Windows Forms程序,以便能夠使用此程序拆分其XML文件。是否有可能在VB Windows窗體內實現XSLT程序? – Woudi

回答

0

謝謝你爲所有人upport!

使用Bibek喬達摩的question and answer從你們和其他人蔘考和反饋我想出了以下工作代碼(在一個單獨的類)運來劃分提到的示例XML到含有commonstring單獨的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 
0

我知道你特意問了一個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> 
+0

感謝Blaze。我用你的輸入(轉換爲VB)以及其他反饋來創建我的答案中提到的工作解決方案。我希望這將有助於未來的用戶提供類似的挑戰。 – Woudi