Преобразование ввода XML из нескольких строк в одну строку - PullRequest
1 голос
/ 06 октября 2009

У меня есть такой xml

<address>
   <street>abc</street>
   <number>123</number>
</address>

<address>
   <street>abc1</street>
   <number>345</number>
</address>

...
...
<address>
   <street>xyz</street>
   <number>999</number>
</address>

Я хочу иметь возможность преобразовать это в

<address><street>abc</street><number>123</number></address>
<address><street>abc1</street><number>345</number></address>
...
...
<address><street>xyz</street><number>999</number></address>

Можете ли вы порекомендовать, как мне поступить, я думаю, что sed может помочь, но не смог заставить его работать.

РЕДАКТИРОВАТЬ: XML-файл имеет 100K строк аналогичного вида, отредактированных для отображения правильного ввода и вывода.

Ответы [ 8 ]

4 голосов
/ 06 октября 2009

[XML :: Twig] [1] поставляется с красивым принтером xml xml_pp. Если адресные строки находятся прямо под корнем документа, вы можете использовать его, чтобы максимально приблизиться к нужному результату:

xml_pp -s record_c to_compact.xml

<root>
  <address><street>abc</street><number>123</number></address>
  <address><street>abc1</street><number>345</number></address>
  <address><street>xyz</street><number>999</number></address>
  <address><street>abc</street><number>123</number></address>
  <address><street>abc1</street><number>345</number></address>
  <address><street>xyz</street><number>999</number></address>
</root>

Удаление пробелов в начале адресных строк довольно просто:

xml_pp -s record_c to_compact.xml | perl -p -e's{^\s+}{}'

Если элементы адреса находятся не под корнем, то сообщите нам, и я посмотрю, что можно сделать.

3 голосов
/ 06 октября 2009

Другой вариант - использовать таблицу стилей XSLT, которая копирует все, но копирует только элементы и атрибуты в элементах адреса:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="address">
        <xsl:copy>
            <xsl:apply-templates select="@*|*"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

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

Вы можете запустить таблицу стилей, используя Java, или из командной строки, используя xsltproc.

3 голосов
/ 06 октября 2009

Я не уверен в синтаксисе командной строки для этого, но это регулярное выражение должно сделать это:

// Find:
/>[\n\s]+</
// Replace with:
><

Это позволит удалить только пробелы между элементами (но не внутри них, если только это не раздел CDATA), но вы можете случайно удалить некоторые пробелы, которые вам действительно нужны, например:

<p>here's <i>something</i> <b>interesting</b></p>
// becomes:
<p>here's <i>something</i><b>interesting</b></p>

Вот пример проблемы с CDATA, которую я упомянул:

<element><![CDATA[
    this shouldn't <blah>
    <blah> be touched.
]]></element>

// becomes:
<element><![CDATA[
    this shouldn't <blah><blah> be touched.
]]></element>

Конечно, «правильный» ответ - использовать синтаксический анализатор для чтения файла, а затем снова вывести его с удаленными пробелами и отступами.

2 голосов
/ 06 октября 2009

Вы можете написать SAX-парсер и для каждого события просто записывать элементы в другой файл без новых строк. Это удалит как новые строки, так и ненужные пробелы.

1 голос
/ 06 октября 2009

Вы можете попробовать этот код (Java):

import java.util.Scanner;
import java.io.File;
import java.io.FileWriter;
public class TrimLines {
  public static void main(String[] args){
    try {
        String source = "employee.xml";
        String result = "no-lines-employee.xml";

        System.out.println("removing lines...");
        Scanner s = new Scanner(new File(source));          
        FileWriter w = new FileWriter(result);          
        while(s.hasNext())              
            w.write(s.nextLine());          
        w.close();          
        System.out.println("remove successfull.");
    }
    catch(Exception ex){
        ex.printStackTrace();
    }
  } 
}

Просто укажите исходное XML-имя файла ( исходная переменная ) и целевое XML-имя файла ( результирующая переменная ).

0 голосов
/ 06 октября 2009

Регулярное выражение

(?<=>)\r?\n[ \t]*(?!<address)

будет соответствовать CRLF + пробелам / тегам между тегами, если за ними не следует <address>. Хотя я обычно советую избегать регулярных выражений и парсера, в этом случае, похоже, это значительно облегчает работу.

0 голосов
/ 06 октября 2009

tr - довольно простой способ заменить символ новой строки:

cat addresses.xml | tr -d '\n'

Google для "shell replace newline" также даст множество других вариантов.

0 голосов
/ 06 октября 2009

эта ссылка должна вам помочь. их пример немного сложнее, но его не должно быть сложно изменить в соответствии с вашими потребностями: http://www.unix.com/unix-dummies-questions-answers/40871-remove-carriage-return-between-line.html

-don

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...