2016-06-16 88 views
0

我期待從大型XML文件中提取元素到單個文件,最好是使用命令或腳本。從大型XML提取整個元素到單個文件

問題是,XML格式不正確,並且是專有的,每當我嘗試使用XML工具(如twig或xmlstarlet)時,數據都會不合適地被淹沒,特殊字符會變得混亂。因此,我需要一個簡單的正則表達式匹配和的正是每場比賽所在的文件名重複說match1.xml match2.xml

示例XML源匹配到一個文件(反覆)直接複製:

... 
  <testcase id="001" kind="bvt"> 
    <inputs> 
      <arg1>4</arg1> 
      <arg2>7</arg2> 
    </inputs> 
    <expected>11.00</expected> 
  </testcase> 
  <testcase id="002" kind="drt"> 
    <inputs> 
      <arg1>9</arg1> 
      <arg2>6</arg2> 
    </inputs> 
    <expected>15.00</expected> 
  </testcase> 
  <testcase id="003" kind="bvt"> 
    <inputs> 
      <arg1>5</arg1> 
      <arg2>8</arg2> 
    </inputs> 
    <expected>13.00</expected> 
  </testcase> 
... 

所需的輸出:match2.xml的

... 
  <testcase id="001" kind="bvt"> 
    <inputs> 
      <arg1>4</arg1> 
      <arg2>7</arg2> 
    </inputs> 
    <expected>11.00</expected> 
  </testcase> 
... 

含量::

.. 
  <testcase id="002" kind="drt"> 
    <inputs> 
      <arg1>9</arg1> 
      <arg2>6</arg2> 
    </inputs> 
    <expected>15.00</expected> 
  </testcase> 
... 
match1.xml的 內容0

等等。

這裏有一些正則表達式,我會放在一起,將工作。我所需要的是幫助將一個循環放在一個bash腳本中,以將每個匹配/元素複製到它自己的文件中。

(<testcase*[\s\S]*?<\/testcase>) 
+0

這裏的大多數人可能會阻止使用shell/syntactic/regex工具的XML問題 - 熟悉xslt和使用例如[xalan](https://xalan.apache.org/xalan-j/),它具有在轉換過程中寫出不同文件的擴展名(其他處理器可能也有類似的功能)。如果你確定你的xml總是採用相同的格式,那麼我認爲它可以用gawk完成。 - 我們總是欣賞你看到的代碼,你嘗試但仍然有問題 –

+0

XML是在一個專有格式,是不正確的,所以我非常確定,我將不得不使用sed和正則表達式來簡單地進行貪婪捕獲整個名稱空間並將每個文件複製到單個文件中。我一直使用像twig和xmlstarlett這樣的實用程序遇到的問題是數據變得繁瑣。以下是我在使用實用程序時必須做出的一些讓步。我在* .xml中爲 –

+0

; do sed -i's/\ &/\&/ g'$ i;完成 爲i in * .xml; do sed -i's/\ &\; quot; \\'/ g'$ i;完成 爲i in * .xml; do-sec -i's/SOAP-ENC:arrayType =「xsd:string \ [1 \]」xsi:type =「SOAP-ENC:Array」/ xsi:type =「SOAP-ENC:Array」SOAP-ENC: arrayType =「xsd:string \ [1 \]」/ g'$ i;完成 爲i in * .xml; do sed -i's/xml:space =「preserve」xsi:type =「xsd:string」/ xsi:type =「xsd:string」xml:space =「preserve」/ g'$ i;完成 爲i in * .xml; do sed -i's/xml:space =「preserve」xsi:type =「cm:guid」/ xsi:type =「cm:guid」xml:space =「preserve」/ g'$ i;完成 爲i in * .xml; do sed -i's// g'$ 1;完成 –

回答

0

想通了! Python有一個偉大的正則表達式模塊「re」,我用它來解決這個問題。

下面是我用的python。在這種情況下,元素就是一切(包括換行符回車,換行符特殊字符等),幷包含元素標記(根據需要在此用例中)。

每個對象元素都會增量寫入到它自己的package-0000-package-nnnn文件中,並且內容正是原始文件中的內容(沒有任何問題)! :)

import re 

from re import match 
pattern = re.compile(r'(<object>[\s\S]*?<\/object>)', flags=re.S) 
with open("/temp/Test/package1.xml", 'r') as f: 
    matches = pattern.findall(f.read()) 

for i, match in enumerate(matches): 
    with open("/temp/Test/package-{0:04d}.xml".format(i), 'w') as nf: 
     nf.write(match) 
+0

你的解決方案不使用shell,所以它不完全是你問的 –

3

使用xmllint做解析(假設你的XML是A.XML文件和主節點被命名爲測試用例):

for num in `cat a.xml | xmllint --xpath '/testcases/testcase/@id' - | sed -r 's/[^"]+"([0-9]+)"/\1 /g'`; do 
    cat a.xml | xmllint --xpath "/testcases/testcase[@id=$num]" - > $num.xml; 
done 

首先,我們得到了測試用例的IDS(XPath返回他們在形式上的id="001"因此sed是用來檢索只是數字)。 然後xpath檢索具有適當id的testcase並將其保存到具有id名稱的文件中。

+0

可以使用'xmlstartlet sel'工具完成相同的工作。 – Dummy00001

0

它實際上是一個簡短的代碼段來編寫和測試...這裏,它結合xpath和vtd-xml。

import com.ximpleware.*; 
import java.io.*; 

public class simpleSplit { 
    public static void main(String[] s) throws VTDException,IOException{ 
     VTDGen vg = new VTDGen(); 
     if (!vg.parseFile("d:\\xml\\inputTest.xml", false)) //namespace awareness disabled 
      return; 
     VTDNav vn = vg.getNav(); 
     AutoPilot ap = new AutoPilot(vn); 
     AutoPilot ap2 = new AutoPilot(vn); 
     ap.selectXPath("/root/testcase"); // main xpath expression 
     ap2.selectXPath("@id"); 
     byte[] head = "<root>".getBytes(); 
     byte[] tail = "</root>".getBytes(); 
     int i=0; 
     while((i=ap.evalXPath())!=-1){ 
      String fileName = ap2.evalXPathToString(); 
      FileOutputStream fios = new FileOutputStream("d:\\xml\\"+fileName+".xml"); 
      long l = vn.getElementFragment(); 
      fios.write(head); 
      fios.write(vn.getXML().getBytes(), (int)l, (int)(l>>32)); 
      fios.write(tail); 
      fios.close(); 
     } 
    } 
}