Как вы предлагаете мне это сделать?
Я предлагаю использовать процессор XSLT-2.0 +, например Saxon от Saxonica , для вывода требуемого файла XML. Но другой процессор XSLT-2.0 тоже работает.
Следующая таблица стилей XSLT-2.0 работает в два этапа:
- Извлечение неразобранного текста в
<xsl:variable>
- Разобрать эту (простую) текстовую переменную с помощью RegEx через
<xsl:analyze-string>
- Группировка получающихся плоских узлов XML с
<xsl:for-each-group>
Таким образом, таблица стилей может выглядеть так:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output method="xml" />
<xsl:param name="text-encoding" as="xs:string" select="'utf-8'"/>
<xsl:param name="text-uri" as="xs:string" select="'file:///home/kubuntu/Downloads/input.txt'"/>
<xsl:template match="/">
<XMLRT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="SomeSchema.xsd" bename="The name" status="v" version="1.4" revision="1" type="x-rt">
<!-- Step 1 ### get unparsed text -->
<xsl:variable name="input-text" select="unparsed-text($text-uri, $text-encoding)"/>
<!-- Step 2 ### Apply RegEx to every line to create <Line...> elements -->
<xsl:variable name="xmlStepOne">
<xsl:for-each select="tokenize($input-text,'
')">
<xsl:if test=".!=''"> <!-- Skip empty lines -->
<xsl:analyze-string select="." regex="([^\s]+)\s([^:]+):([^\s]+)\s(.*)$">
<xsl:matching-substring> <!-- Parse line with RegEx and create <Line...> XML -->
<Line str="{regex-group(1)}" idx1="{regex-group(2)}" idx2="{regex-group(3)}"><xsl:value-of select="regex-group(4)"/></Line>
</xsl:matching-substring>
<xsl:non-matching-substring> <!-- Output an error if a line cannot be processed -->
<xsl:message terminate="yes">Error processing line 
<xsl:value-of select="current()"/>
</xsl:message>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<!-- Step 3 ### Group the linear flow of <Line...> elements -->
<xsl:for-each-group select="$xmlStepOne/Line" group-by="@str">
<RTBLOCK bname="{current-grouping-key()}" bnumber="1" bsname="{concat('1',substring(current-grouping-key(),1,1))}">
<xsl:for-each-group select="current-group()" group-by="@idx1">
<xsl:sort select="@idx1" />
<CTR cnumber="{@idx1}">
<xsl:for-each select="current-group()">
<xsl:sort select="@idx2" />
<ES vnumber="{@idx2}"><xsl:value-of select="."/></ES>
</xsl:for-each>
</CTR>
</xsl:for-each-group>
</RTBLOCK>
</xsl:for-each-group>
</XMLRT>
</xsl:template>
</xsl:stylesheet>
Вы можете установить имя входного файла и кодировку с двумя параметрами в начале.
Выходные данные из файла примера выше:
<?xml version="1.0" encoding="UTF-8"?>
<XMLRT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="SomeSchema.xsd" bename="The name" status="v" version="1.4" revision="1" type="x-rt">
<RTBLOCK bname="Usw" bnumber="1" bsname="1U">
<CTR cnumber="1">
<ES vnumber="1">Desktop</ES>
<ES vnumber="2">Netbooks</ES>
<ES vnumber="3">Servers, mainframes and supercomputers</ES>
<ES vnumber="4">Smart devices</ES>
<ES vnumber="5">Embedded devices</ES>
<ES vnumber="6">Gaming</ES>
<ES vnumber="7">Specialized uses</ES>
</CTR>
<CTR cnumber="2">
<ES vnumber="1">Precursors</ES>
<ES vnumber="2">Creation</ES>
<ES vnumber="5">Naming</ES>
<ES vnumber="6">Commercial and popular uptake</ES>
<ES vnumber="9">Current development</ES>
</CTR>
</RTBLOCK>
<RTBLOCK bname="Des" bnumber="1" bsname="1D">
<CTR cnumber="1">
<ES vnumber="1">User interface</ES>
<ES vnumber="2">Video input infrastructure</ES>
<ES vnumber="3">Hardware</ES>
</CTR>
<CTR cnumber="2">
<ES vnumber="1">Community</ES>
<ES vnumber="2">Programming on Linux</ES>
</CTR>
</RTBLOCK>
</XMLRT>
Еще одним преимуществом этого подхода является то, что вы можете обрабатывать все с помощью XML / XSLT, и поэтому он знает о кодировке символов и обо всем, что не охватывается более простыми решениями с awk
или аналогичными.