Преобразование необработанных данных в настроенный XML - PullRequest
0 голосов
/ 03 октября 2019

Я хочу преобразовать необработанный файл в следующий формат, используя Java -

Необработанный ввод:

state | abc
country | FR-FRA

Вывод:

<data attr ="StateFr">abc</data>
<data attr ="country">FR-FRA</data>

Атрибут состояния должен бытьс кодом страны, указанным выше. Может ли кто-нибудь помочь мне в этом.

Ответы [ 3 ]

1 голос
/ 03 октября 2019

Java Stream API может помочь

    String raw ="name1|value1\n" +
                    "name2|value2";
    String template = "<data attribute=\"%s\">%s</data>";
    String output = Arrays.stream(raw.split("\n"))
            .map(rawPair -> rawPair.split("\\|"))
            .map(pair -> String.format(template, pair[0], pair[1]))
            .collect(Collectors.joining("\n"));

будет выводить

<data attribute="name1">value1</data>
<data attribute="name2">value2</data>

Но наличие определенной бизнес-логики требует немного больше движений. Сначала получите код страны , а затем украсьте имя вашего атрибута при обработке потока

    BiFunction<String, String, String> decorate = (String name, String code) -> {
        if ("state".equals(name)) {
            return name + code;
        } else {
            return name;
        }
    };
    Function<String, String> countryCode = (String source) -> {
        String head = "country|";
        int start = source.indexOf(head) + head.length();
        return source.substring(start, start + 2);
    };

    String code = countryCode.apply(raw);

    ...
    .map(pair -> String.format(template, decorate.apply(pair[0], code), pair[1]))
    ...
0 голосов
/ 03 октября 2019

Запустите следующую таблицу стилей XSLT 3.0:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
     version="3.0" expand-text="yes" xmlns:f="f">

<xsl:template name="xsl:initial-template">
 <root>
  <xsl:iterate select="unparsed-text-lines('input.txt')">
    <xsl:param name="prev-parts" select="()"/>
    <xsl:on-completion>
       <attribute name="{$prev-parts[1]}">{$prev-parts[2]}</attribute>
    </xsl:on-completion>  
    <xsl:variable name="parts" select="tokenize(., '\|')"/>
    <xsl:choose>
      <xsl:when test="$parts[1] = 'country'">
        <attribute name="{f:titleCase($prev-parts[1])}{f:titleCase(substring-before($parts[2], '-')}">{$prev-parts[2]}</attribute>
      </xsl:when>
      <xsl:otherwise>
        <attribute name="{$prev-parts[1]}>{$prev-parts[2]}</attribute>
      </xsl:otherwise>
    </xsl:choose>
    <xsl:next-iteration>
      <xsl:with-param name="prev-parts" select="$parts"/>
    </xsl:next-iteration>
  </xsl:iterate>
 </root>
</xsl:template>

<xsl:function name="f:titleCase">
  <xsl:param name="in"/>
  <xsl:sequence select="upper-case(substring($in, 1, 1))||substring($in, 2)"/>
</xsl:function>    
</xsl:transform>

Обратите внимание, что в отличие от других решений, представленных здесь, это всегда будет давать правильно сформированный вывод XML. (Мы видим очень много проблем в StackOverflow от людей, получающих так называемый XML, который был сгенерирован неправильно, потому что он игнорирует проблему экранирования специальных символов.)

0 голосов
/ 03 октября 2019

С новыми требованиями

  1. необработанный файл имеет большой размер
  2. необработанный файл имеет код страны, следующий за состоянием
  3. чтение файла один за другим.
  4. также требуется выводить преобразованные записи в том же порядке, в котором они отображаются в необработанном источнике.

вам следует

  1. распознать sate и сохраните ее, пока не создайте следующую запись
  2. распознайте последующую страну , обновите состояние сохраните и отпустите состояние и contry entry

, поэтому здесь я использую тип мелкого буфера для этой роли

    String raw = "name|value1\n" +
            "state|some-state1\n" +
            "country|fr-fra\n" +
            "name|value2\n" +
            "state|some-state2\n" +
            "country|en-us\n";

    class ShallowBuffer {
        private String stateKey = "state";
        private String countryKey = "country";
        private String[] statePairWaitingForCountryCode = null;

        private List<String[]> pump(String[] pair) {
            if (stateKey.equals(pair[0])) {
                statePairWaitingForCountryCode = pair;
                return Collections.emptyList();
            }
            if (countryKey.equals(pair[0])) {
                statePairWaitingForCountryCode[0] = statePairWaitingForCountryCode[0] + pair[1].substring(0, 2);
                String[] stateRelease = statePairWaitingForCountryCode;
                statePairWaitingForCountryCode = null;
                return Arrays.asList(stateRelease, pair);
            }
            return Collections.singletonList(pair);
        }
    }

    ShallowBuffer patience = new ShallowBuffer();
    String template = "<data attribute=\"%s\">%s</data>";
    String output = Arrays.stream(raw.split("\n"))
            .map(rawPair -> rawPair.split("\\|"))
            .map(patience::pump)
            .flatMap(Collection::stream)
            .map(pair -> String.format(template, pair[0], pair[1]))
            .collect(Collectors.joining("\n"));

это выдаст

 <data attribute="name">value1</data>
 <data attribute="statefr">some-state1</data>
 <data attribute="country">fr-fra</data>
 <data attribute="name">value2</data>
 <data attribute="stateen">some-state2</data>
 <data attribute="country">en-us</data>

Мелкий буфер является изменяемым, поэтому вы не можете использовать параллельные методы в вашей цепочке потоков. Это также означает, что маркировка его как доступного за пределами области действия потребует синхронизации. И вам все еще нужно использовать заглавную букву кода страны)

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