2016-07-28 2 views
-1

У меня есть большой xml-файл размером 10 Гб, и я хочу создать новый XML-файл, который создается из первой записи большого файла. Я попытался сделать это в java и python, но у меня появилась ошибка памяти, m загрузить все данные.Как сгенерировать файл xml, взяв первую запись из большого xml-файла размером 10gb без получения ошибки памяти?

В другом посте, кто-то предложил XSLT является лучшим решением для this.I'm новой для XSLT, я не знаю, как сделать это в XSLT, пожалуйста предложить некоторые таблицы стилей, чтобы сделать это ...

Большой XML-файл (10gb) образец:

<MemberDataExport xmlns="http://www.payback.net/lmsglobal/batch/memberdataexport" xmlns:types="http://www.payback.net/lmsglobal/xsd/v1/types"> 
    <MembershipInfoListItem> 
     <MembershipIdentifier>PB00000000001956044</MembershipIdentifier> 
     <ParticipationStatus>1</ParticipationStatus> 
     <DataSharing>1</DataSharing> 
     <MasterInfo> 
      <Gender>1</Gender> 
      <Salutation>1</Salutation> 
      <FirstName>Hazel</FirstName> 
      <LastName>Sweetman</LastName> 
      <DateOfBirth>1957-03-25</DateOfBirth> 
     </MasterInfo> 
    </MembershipInfoListItem> 
    <Header> 
    <BusinessPartner>CHILIS_US</BusinessPartner> 
    <FileType>mde</FileType> 
    <FileNumber>17</FileNumber> 
    <FormatVariant>1</FormatVariant> 
    <NumberOfRecords>22</NumberOfRecords> 
    <CreationDate>2016-06-07T12:00:46-07:00</CreationDate> 
    </Header> 
     <MembershipInfoListItem> 
     <MembershipIdentifier>PB00000000001956044</MembershipIdentifier> 
     <ParticipationStatus>1</ParticipationStatus> 
     <DataSharing>1</DataSharing> 
     <MasterInfo> 
      <Gender>1</Gender> 
      <Salutation>1</Salutation> 
      <FirstName>Hazel</FirstName> 
      <LastName>Sweetman</LastName> 
      <DateOfBirth>1957-03-25</DateOfBirth> 
     </MasterInfo> 
    </MembershipInfoListItem> 
..... 
..... 
</MemberDataExport> 

Я хочу, чтобы создать файл, как это ..

<MemberDataExport xmlns="http://www.payback.net/lmsglobal/batch/memberdataexport" xmlns:types="http://www.payback.net/lmsglobal/xsd/v1/types"> 
     <MembershipInfoListItem> 
      <MembershipIdentifier>PB00000000001956044</MembershipIdentifier> 
      <ParticipationStatus>1</ParticipationStatus> 
      <DataSharing>1</DataSharing> 
      <MasterInfo> 
       <Gender>1</Gender> 
       <Salutation>1</Salutation> 
       <FirstName>Hazel</FirstName> 
       <LastName>Sweetman</LastName> 
       <DateOfBirth>1957-03-25</DateOfBirth> 
      </MasterInfo> 
     </MembershipInfoListItem> 
</MemberDataExport> 

есть ли другой способ, я могу это сделать без ошибки памяти? PLS предположить, что тоже.

+0

вы можете также показать код Java вы пробовали? – JammuPapa

+0

Используйте синтаксический анализатор SAX для получения первого элемента и нажмите его с помощью преобразования XSL –

ответ

0

В Python (который вы упомянули, кроме Java) можно использовать ElementTree.iterparse и затем перерыв разбора, когда вы нашли элемент (ы) вы хотите скопировать:

import xml.etree.ElementTree as ET 
count = 0 
copy = 1 # set this to the number of second level (i.e. children of the root) elements you want to copy 
level = -1 

for event, elem in ET.iterparse('input1.xml', events = ('start', 'end')): 
    if event == 'start': 
     level = level + 1 
     if level == 0: 
      result = ET.ElementTree(ET.Element(elem.tag)) 

    if event == 'end': 
     level = level - 1 
     if level == 0: 
      count = count + 1 
      if count <= copy: 
       result.getroot().append(elem) 
      else: 
       break 



result.write('result1.xml', 'UTF-8', True, 'http://www.payback.net/lmsglobal/batch/memberdataexport') 

Как для лучшего пространства имен сохранения приставки, я имел некоторый успех, используя событие start-ns и регистрирующий собранные пространства имен на ElementTree:

import xml.etree.ElementTree as ET 
count = 0 
copy = 1 # set this to the number of second level (i.e. children of the root) elements you want to copy 
level = -1 

for event, elem in ET.iterparse('input1.xml', events = ('start', 'end', 'start-ns')): 
    if event == 'start': 
     level = level + 1 
     if level == 0: 
      result = ET.ElementTree(ET.Element(elem.tag)) 

    if event == 'end': 
     level = level - 1 
     if level == 0: 
      count = count + 1 
      if count <= copy: 
       result.getroot().append(elem) 
      else: 
       break 

    if event == 'start-ns': 
     ET.register_namespace(elem[0], elem[1]) 


result.write('result1.xml', 'UTF-8', True) 
+0

- этот код работает нормально, но если xml содержит пространство имен, например xmlns: h = "http://www.w3.org/TR/html4/ «В большом файле сгенерированный файл содержит такой xmlns: ns0 =« http://www.w3.org/TR/html4/ ». Но мне нужен только оригинальный префикс, любое решение для этого? – mariz

+0

Кажется, что пространства имен сообщаются 'iterparse' как отдельные события' start-ns' и 'end-ns', где' elem' является кортежем '(prefix, namespaceURI)', но я не обнаружил, как их копировать на элементы, зачитанные в событии 'end', или как убедиться, что сериализация с помощью метода' write' использует эти пространства имен. –

+0

@mariz, я отредактировал ответ со вторым образцом, который также собирает события «start-ns» и регистрирует их на «ElementTree», таким образом кажется, что сериализация, выполненная с помощью вызова 'write', использует их, по крайней мере здесь с Python 3.4. –

0

Вы не указали свой код, поэтому мы не можем знать, что вы делаете правильно или неправильно. Тем не менее, я бы поставил на то, что любой парсер должен будет загрузить весь файл, чтобы проверить, нет ли синтаксиса, отсутствующих тегов и т. Д., И это наверняка вызовет ошибку OutOfMemory для файла размером 10 ГБ.
Так, только в этом случае, мой подход был бы прочитать файл построчно с помощью BufferedStreamReader (см How to read a large text file line by line using Java?) и просто остановиться, когда вы достигаете строку, содержащую ваш закрывающий тег, т.е. </MembershipInfoListItem>:

StringBuilder sb = new StringBuilder("<MemberDataExport xmlns=\"http://www.payback.net/lmsglobal/batch/memberdataexport\" xmlns:types=\"http://www.payback.net/lmsglobal/xsd/v1/types\">"); 
sb.append(System.lineSeparator()); 
try (BufferedReader br = new BufferedReader(new FileReader(file))) { 
    String line; 
    while ((line = br.readLine()) != null) { 
     // process the line 
     sb.append(line); 
     sb.append(System.lineSeparator()); 
     if (line.contains("</MembershipInfoListItem>")) { 
      break; 
     } 
    } 
    sb.append("</MemberDataExport>"); 
} catch (IOException | AnyOtherExceptionNeeded ex) { 
    // log or rethrow 
} 

Теперь sb.toString() вернет вам то, что вы хотите.