Создать XML-формат из файла TXT - PullRequest
0 голосов
/ 28 апреля 2018

У меня есть входной текстовый файл ниже, и я пытаюсь сгенерировать файл XMl ниже. Я пытаюсь сделать это с помощью awk, но Я думаю, что я заново изобретаю колесо. Как вы предлагаете мне это сделать? Спасибо

Входной текстовый файл (пример, этот вход может быть больше)

Usw 1:1 Desktop
Usw 1:2 Netbooks
Usw 1:3 Servers, mainframes and supercomputers
Usw 1:4 Smart devices
Usw 1:5 Embedded devices
Usw 1:6 Gaming
Usw 1:7 Specialized uses
Usw 2:1 Precursors
Usw 2:2 Creation
Usw 2:5 Naming
Usw 2:6 Commercial and popular uptake
Usw 2:9 Current development
Des 1:1 User interface
Des 1:2 Video input infrastructure
Des 1:3 Hardware
Des 2:1 Community
Des 2:2 Programming on Linux

желаемый XML-файл

<?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">
<INTRO>
    <title>Some title</title>
    <creator>
    </creator>
    <subject>Some subject</subject>
    <description>Some description</description>
    <date>2010-05-12</date>
    <type>Some text</type>
</INTRO>
<RTBLOCK bname="Usw" bnumber="1" bsname="1U">
    <CTR cnumber="1">
    <ES vnumber="1">Desktop</ES>
    <ES vnumber="2">Netbooks</ES>
    <ES vnumber="3">SerES, 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>

Ответы [ 2 ]

0 голосов
/ 29 апреля 2018

Как вы предлагаете мне это сделать?

Я предлагаю использовать процессор XSLT-2.0 +, например Saxon от Saxonica , для вывода требуемого файла XML. Но другой процессор XSLT-2.0 тоже работает.

Следующая таблица стилей XSLT-2.0 работает в два этапа:

  1. Извлечение неразобранного текста в <xsl:variable>
  2. Разобрать эту (простую) текстовую переменную с помощью RegEx через <xsl:analyze-string>
  3. Группировка получающихся плоских узлов 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,'&#xa;')">
                    <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 &#xa;<xsl:value-of select="current()"/>&#xa;</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 или аналогичными.

0 голосов
/ 29 апреля 2018

Просто чтобы показать, что вам не нужен инструмент с поддержкой XML для генерации конкретного XML, который вам нужен для любой конкретной цели, вот один из способов сделать это для вашего примера:

$ cat tst.awk
BEGIN {
    print    "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
    print    ""
    print    "<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\">"
    print    "<INTRO>"
    print    "    <title>Some title</title>"
    print    "    <creator>"
    print    "    </creator>"
    print    "    <subject>Some subject</subject>"
    print    "    <description>Some description</description>"
    print    "    <date>2010-05-12</date>"
    print    "    <type>Some text</type>"
    print    "</INTRO>"

    rtBeg  = "<RTBLOCK bname=\"%s\" bnumber=\"1\" bsname=\"1%s\">\n"
    ctrBeg = "    <CTR cnumber=\"%d\">\n"
    esBody = "    <ES vnumber=\"%d\">%s</ES>\n"
    ctrEnd = "    </CTR>\n"
    rtEnd  = "</RTBLOCK>\n"
    xmlEnd = "</XMLRT>\n"
}
{
    bname = $1

    split($2,tmp,/:/)
    cnum = tmp[1]
    vnum = tmp[2]

    text = $0
    sub(/([^[:space:]]+[[:space:]]+){2}/,"",text)
}

bname != prevBname {
    if (prevCnum  != "") printf ctrEnd
    if (prevBname != "") printf rtEnd
    printf rtBeg, bname, substr(bname,1,1)
    prevCnum = ""
    prevBname = bname
}

cnum != prevCnum {
    if (prevCnum != "") printf ctrEnd
    printf ctrBeg, cnum
    prevCnum = cnum
}

{ printf esBody, vnum, text }

END {
    if (prevCnum  != "") printf ctrEnd
    if (prevBname != "") printf rtEnd
    printf xmlEnd
}

.

$ awk -f tst.awk file
<?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">
<INTRO>
    <title>Some title</title>
    <creator>
    </creator>
    <subject>Some subject</subject>
    <description>Some description</description>
    <date>2010-05-12</date>
    <type>Some text</type>
</INTRO>
<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>

Вышеописанное будет работать эффективно, надежно и переносимо с любым POSIX awk в любой оболочке на любом компьютере UNIX.

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