Утверждения, что: (XSLT) "isn't suitable for transforming from structured text to XML. "
и утверждение "XSLT
must
have XML as the input document"
** оба неверны .
Я думаю, 2 подхода
Определите бизнес-сущность и заполните свойства сущности, используя функции подстроки во входном тексте, а затем сериализуйте сущность в
XML
Предварительно определите структуру 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, '
')">
<xsl:variable name="vLine" select=
"substring-before($pText, '
')"/>
<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, '
')"/>
</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>
Примечания :
Это просто демонстрация, демонстрирующая, как выполнить задачу. Вот почему я не обрабатываю поля фиксированной ширины (хотя было бы еще проще), а разделяю их пробелами.
Любое пространство, содержащееся в любом значении, вводится в качестве подчеркивания (или любого другого символа по нашему выбору, который, как мы знаем, никогда не будет частью какого-либо значения. При выводе любое подчеркивание преобразуется в реальное пространство).
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, '
?
')[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>
Примечания
Использование стандартной функции XSLT 2.0 unparsed-text()
.
Использование стандартной функции XPath 2.0 tokenize()
.
Конечная нота :
Наиболее сложная обработка текста была выполнена промышленным способом полностью в XSLT. Библиотека FXSL содержит универсальный LR (1) синтаксический анализатор и настроенный YACC, который производит XML-форматированный таблицы , которые являются входными данными для этого универсального анализатора LR (1) времени выполнения.
Используя этот инструмент, я успешно построил парсеры для таких сложных языков, как JSON и XPath 2.0.