2016-06-16 2 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> 
... 

Желаемый результат: Содержание match1.xml:

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

Содержание match2.xml:

.. 
  <testcase id="002" kind="drt"> 
    <inputs> 
      <arg1>9</arg1> 
      <arg2>6</arg2> 
    </inputs> 
    <expected>15.00</expected> 
  </testcase> 
... 

и так далее.

Вот несколько регулярных выражений, которые я собрал вместе, которые будут работать. Все, что мне нужно, - это помощь по объединению цикла в скрипте bash для копирования каждого элемента match/element в его собственный файл.

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

Большинство людей здесь, вероятно, будут препятствовать использованию инструментов оболочки/синтаксиса/регулярных выражений для проблем xml - ознакомьтесь с xslt и используйте, например. [xalan] (https://xalan.apache.org/xalan-j/), который имеет расширение для записи разных файлов во время преобразования (другие процессоры могут иметь что-то подобное). Если вы уверены, что ваш xml всегда приходит в том же форматировании, то я думаю, что это можно сделать с помощью gawk. - Мы всегда ценим, что код, который вы пытаетесь, но все еще имеет проблемы –

+0

XML находится в запатентованном формате, который не очень хорошо сформирован, поэтому я уверен, что мне придется что-то использовать с sed и regex, чтобы просто сделать жадный захват целые пространства имен и скопировать их в отдельный файл. Проблема, с которой я продолжаю работать в таких утилитах, как twig и xmlstarlett, заключается в том, что данные замалчиваются.Вот некоторые фрагменты уступок, которые я должен был сделать при использовании утилит. –

+0

для i в * .xml; do sed -i 's/\ &/\ &/g' $ i; сделано для i in * .xml; do sed -i 's/\ &\; quot/\ & quot; g' $ i; сделано для i in * .xml; do sed -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 = "сохранить" xsi: type = "xsd: string"/xsi: type = "xsd: string" xml: space = "preserve"/g' $ i; сделано для i in * .xml; do sed -i 's/xml: space = "сохранить" xsi: type = "cm: guid"/xsi: type = "cm: guid" xml: space = "preserve"/g' $ i; сделано для i in * .xml; do sed -i 's/Â // g' $ 1; done –

ответ

0

Придумал! Python имеет отличный regex-модуль «re», который я использовал для решения этой проблемы.

Ниже приведен питон, который я использовал. В этом случае элементом было все (включая перематывание строк, возврат строк, специальные символы и т. Д.) До и включает в себя тег элемента (как это необходимо в этом случае использования).

Каждый элемент объекта получает инкрементно записанный в его собственный пакет-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

Ваше решение не использует оболочку, так что это не совсем то, что вы просили –

3

Использование xmllint делать разбор (если ваш XML в a.xml файл и основной узел называется testcases):

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 

Сначала мы получаем TestCase идентификаторы (XPath возвращает их в виде id="001", поэтому sed используется для извлечения только цифр). Затем xpath извлекает только тестовый файл с соответствующим идентификатором и сохраняет его в файле с именем 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(); 
     } 
    } 
} 
Смежные вопросы