Является ли xslt хорошим подходом для преобразования текста в структуру xml? - PullRequest
3 голосов
/ 21 ноября 2011

Я пытаюсь найти лучшее решение для преобразования простого текста (но с предопределенной длиной для каждого поля) в xml. Например, вводимый текст может быть «Testuser New York 10018», первые 11 символов указывают имя пользователя, следующие 12 символов указывают город и следующие 5 символов указывают почтовый индекс. Поэтому мне нужно сформировать xml из приведенной выше строки с предварительно определенной длиной поля.

Я думаю, 2 подхода

  1. Определите бизнес-сущность и заполните свойства сущности, используя функции подстроки во входном тексте, а затем сериализуйте сущность в xml

  2. Предварительно определите структуру xml, используйте xslt для перехода к каждому узлу и заполните значения использование функций подстроки во вводимом тексте.

Ответы [ 2 ]

5 голосов
/ 21 ноября 2011

Утверждения, что: (XSLT) "isn't suitable for transforming from structured text to XML. " и утверждение "XSLTmusthave XML as the input document" ** оба неверны .

Я думаю, 2 подхода

  1. Определите бизнес-сущность и заполните свойства сущности, используя функции подстроки во входном тексте, а затем сериализуйте сущность в XML

  2. Предварительно определите структуру xml, используйте xslt для перехода к каждому узлу и заполните значения с помощью подстрок во входном тексте.

На самом деле, подход 2 довольно легко реализовать с помощью XSLT :

I. XSLT 1.0 :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/*/text()" name="processLines">
  <xsl:param name="pText" select="."/>

  <xsl:if test="contains($pText, '&#xA;')">
    <xsl:variable name="vLine" select=
     "substring-before($pText, '&#xA;')"/>

     <user>
       <name>
         <xsl:value-of select=
         "translate(substring-before($vLine, ' '),'_',' ')"/>
       </name>
       <city>
         <xsl:value-of select=
         "translate(substring-before(substring-after($vLine, ' '),' '),
                    '_',
                    ' '
                    )
         "/>
       </city>
       <zipCode>
         <xsl:value-of select=
         "translate(substring-after(substring-after($vLine, ' '),' '),
                    '_',
                    ' '
                    )
         "/>
       </zipCode>
     </user>

     <xsl:call-template name="processLines">
      <xsl:with-param name="pText" select=
      "substring-after($pText, '&#xA;')"/>
     </xsl:call-template>
  </xsl:if>
  </xsl:template>
</xsl:stylesheet>

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

<t>Testuser new_york 10018
usera seattle 98000
userb bellevue 98004
userb redmond 98052
</t>

желаемый результат получен :

<user>
   <name>Testuser</name>
   <city>new york</city>
   <zipCode>10018</zipCode>
</user>
<user>
   <name>usera</name>
   <city>seattle</city>
   <zipCode>98000</zipCode>
</user>
<user>
   <name>userb</name>
   <city>bellevue</city>
   <zipCode>98004</zipCode>
</user>
<user>
   <name>userb</name>
   <city>redmond</city>
   <zipCode>98052</zipCode>
</user>

Примечания :

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

  2. Любое пространство, содержащееся в любом значении, вводится в качестве подчеркивания (или любого другого символа по нашему выбору, который, как мы знаем, никогда не будет частью какого-либо значения. При выводе любое подчеркивание преобразуется в реальное пространство).

II. Решение XSLT 2.0 :

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vText" select=
  "unparsed-text('file:///c:/temp/delete/delete.txt')"/>

 <xsl:variable name="vLines" select=
  "tokenize($vText, '&#xD;?&#xA;')[normalize-space()]"/>

 <xsl:template match="/">
  <xsl:for-each select="$vLines">
    <xsl:variable name="vFields" select=
    "tokenize(., ' ')[normalize-space()]"/>
   <user>
     <name>
       <xsl:sequence select="translate($vFields[1], '_',' ')"/>
     </name>
     <city>
       <xsl:sequence select="translate($vFields[2], '_',' ')"/>
     </city>
     <zipCode>
       <xsl:sequence select="translate($vFields[3], '_',' ')"/>
     </zipCode>
   </user>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

когда это преобразование применяется к любому документу XML (не используется и фактически не требуется, так как в XSLT 2.0 нет необходимости иметь исходный документ XML), и , если файл C:\temp\delete\delete.txt is :

Testuser new_york 10018
usera seattle 98000
userb bellevue 98004
userb redmond 98052

снова желаемый, правильный результат выдается :

<user>
   <name>Testuser</name>
   <city>new york</city>
   <zipCode>10018</zipCode>
</user>
<user>
   <name>usera</name>
   <city>seattle</city>
   <zipCode>98000</zipCode>
</user>
<user>
   <name>userb</name>
   <city>bellevue</city>
   <zipCode>98004</zipCode>
</user>
<user>
   <name>userb</name>
   <city>redmond</city>
   <zipCode>98052</zipCode>
</user>

Примечания

  1. Использование стандартной функции XSLT 2.0 unparsed-text().

  2. Использование стандартной функции XPath 2.0 tokenize().

Конечная нота :

Наиболее сложная обработка текста была выполнена промышленным способом полностью в XSLT. Библиотека FXSL содержит универсальный LR (1) синтаксический анализатор и настроенный YACC, который производит XML-форматированный таблицы , которые являются входными данными для этого универсального анализатора LR (1) времени выполнения.

Используя этот инструмент, я успешно построил парсеры для таких сложных языков, как JSON и XPath 2.0.

3 голосов
/ 21 ноября 2011

XSLT 2.0 отлично подходит для преобразования структурированного текста в XML.Вам может понравиться статья 2010 года Стефани Хаупт и Майка Штюренберга здесь:

http://www.balisage.net/Proceedings/vol5/html/Haupt01/BalisageVol5-Haupt01.html

или моя собственная статья 2008 года

http://www.saxonica.com/papers/ideadb-1.1/mhk-paper.xml

для тематических исследований.

Обычно я не пытался бы выполнить задачу, используя XSLT 1.0, хотя, как показывает ответ Димитра, это можно сделать в простых случаях.

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