Преобразовать INI в XML? ИЛИ любой универсальный устаревший плоский файл? XSL? из xmlstarlet или xsltproc?

Я хочу сделать какое-то преобразование из INI в XML, синтаксис INI прост. Я не ищу sed/awk/grep, это действительно нужно делать в инструментах XML.

Можно ли это сделать с помощью обычного XSL? Я слышал о Xflat, но могу ли я сделать это с помощью инструментов, скомпилированных на C? Например, xsltproc или xmlstarlet.

Общий синтаксис INI выглядит так...

[section]
option = values

который будет в xml, как это...

<section>
<option>values</option>
</section>

Любая помощь будет очень признательна.


person J. M. Becker    schedule 08.12.2011    source источник
comment
Пожалуйста, научитесь правильно форматировать код XML/XSLT, чтобы он был виден. Подсказка: выберите код и нажмите на значок {}.   -  person Dimitre Novatchev    schedule 08.12.2011
comment
Ваш вопрос привлечет больше внимания, если вы на самом деле предоставите конкретный образец ini-файла — не оставляйте свою часть работы (определение проблемы) незавершенной и не оставляйте бремя создания фактического образца на ваших читателей.   -  person Dimitre Novatchev    schedule 08.12.2011
comment
Я предоставил образец, INI буквально настолько прост. Просто целая страница этих блоков INI.   -  person J. M. Becker    schedule 10.12.2011
comment
этот инструмент работал у меня whiterocksoftware.com/2018/12 /convert-ini-file-to-xml.html Преобразует все разделы ini в разделы xml, а группы ini name=values ​​в элементы xml внутри раздела группы.   -  person Pomodoro Technique Game    schedule 30.12.2018


Ответы (3)


Можно ли это сделать с помощью обычного XSL?

Да, и XSLT 2.0 предоставляет больше возможностей для обработки текста, чем XSLT 1.0. В XSLT реализована очень сложная обработка текста, включая общий синтаксический анализатор LR(1), используемый для создания синтаксических анализаторов для конкретные грамматики, такие как JSON и XPath.

В частности, узнайте о unparsed-text(), различные строковые функции< /strong>, включая те, которые позволяют использовать регулярные выражения (matches()< /a>, tokenize() и replace()), а также инструкция <xsl:analyze-string> .

XSLT 1.0 также имеет строковые функции (предусмотренные XPath 1.0), однако ему не хватает возможностей/функций регулярных выражений, и нет ничего подобного функции XSLT 2.0 unparsed-text(). Среди наиболее полезных строковых функций XPath 1.0: substring(), substring-before(), substring-after(), starts-with(), string-length(), concat() и особенно translate().

Можно «прочитать» файл, используя объект в DTD, как объяснил Мэдс Хансен в своем ответе. Другой способ — прочитать файл в программе, которая инициирует преобразование, а затем передать содержимое файла в виде строкового параметра преобразованию.

Обновление: теперь ОП предоставила конкретные данные, так что возможно полное решение:

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

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

 <xsl:variable name="vLines" as="xs:string*" select=
   "tokenize($vText, '&#xD;?&#xA;')[.]"/>

 <xsl:variable name="vLineCnt" select="count($vLines)"/>

 <xsl:variable name="vSectLinesInds" as="xs:integer*" select=
  "for $i in 1 to $vLineCnt
     return
       if(starts-with(normalize-space($vLines[$i]), '['))
         then $i
         else ()
  "/>

 <xsl:variable name="vSectCnt" select="count($vSectLinesInds)"/>

 <xsl:template match="/">
  <xsl:for-each select="$vSectLinesInds">
    <xsl:variable name="vPos" select="position()"/>
    <xsl:variable name="vInd" as="xs:integer" select="."/>

     <xsl:variable name="vthisLine" as="xs:string"
          select="$vLines[$vInd]"/>

    <xsl:variable name="vNextSectInd" select=
     "if($vPos eq $vSectCnt)
        then
          $vLineCnt +1
        else
          $vSectLinesInds[$vPos +1]
     "/>

   <xsl:variable name="vInnerLines" select=
   "$vLines
       [position() gt current()
      and
        position() lt $vNextSectInd
       ]

   "/>

   <xsl:variable name="vName" select=
    "tokenize($vthisLine, '\[|\]')[2]"/>

   <xsl:element name="{$vName}">
    <xsl:for-each select="$vInnerLines">
      <xsl:variable name="vInnerParts" select=
      "tokenize(., '[ ]*=[ ]*')"/>

      <xsl:element name="{$vInnerParts[1]}">
        <xsl:value-of select="$vInnerParts[2]"/>
      </xsl:element>
    </xsl:for-each>
  </xsl:element>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

когда это преобразование применяется к любому XML-документу (не используется) и если файл в C:\temp\delete\test.ini имеет следующее содержимое:

[section1]
option1 = values1
option2 = values2
option3 = values3
option4 = values4
option5 = values5

[section2]
option1 = values1
option2 = values2
option3 = values3
option4 = values4
option5 = values5

[section3]
option1 = values1
option2 = values2
option3 = values3
option4 = values4
option5 = values5

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

<section1>
   <option1>values1</option1>
   <option2>values2</option2>
   <option3>values3</option3>
   <option4>values4</option4>
   <option5>values5</option5>
</section1>
<section2>
   <option1>values1</option1>
   <option2>values2</option2>
   <option3>values3</option3>
   <option4>values4</option4>
   <option5>values5</option5>
</section2>
<section3>
   <option1>values1</option1>
   <option2>values2</option2>
   <option3>values3</option3>
   <option4>values4</option4>
   <option5>values5</option5>
</section3>
person Dimitre Novatchev    schedule 08.12.2011

Да, вы можете анализировать обычный текстовый файл в XSLT

Вероятно, было бы проще сделать это в XSLT 2.0, если вам это подходит.

В XSLT 2.0: вы можете использовать unparsed-text( ) для чтения файла, tokenize() чтобы разделить его на строки.

<xsl:for-each select="tokenize(unparsed-text($in), '\r?\n')">
 ...
</xsl:for-each>

В XSLT 1.0: вы можете читать многие простые текстовые файлы, включив их в XML-файл, ссылаясь на текстовый файл с внешним объектом (если они не содержат никаких символы/шаблоны, которые могут привести к ошибкам синтаксического анализа XML). Текст из файла будет включен в файл XML по мере его анализа.

<!DOCTYPE foo [
<!ENTITY bar SYSTEM "bar.txt">
]>
<foo>
&bar;
</foo>
person Mads Hansen    schedule 08.12.2011
comment
Этот метод будет работать для многих файлов, но не для тех, которые содержат ‹ или & или ]]›, или для различных других вещей, которые синтаксический анализатор XML будет обрабатывать специально. - person Michael Kay; 08.12.2011
comment
@Майкл Кей - Да, хорошая мысль. Я добавил предостережение для решения сущности XSLT 1.0. - person Mads Hansen; 08.12.2011

Если вы можете использовать процессор XSLT 2.0, у вас есть функция unparsed-text(), которая может импортировать плоские файлы.

После того, как файл импортирован, у вас есть традиционные строковые инструменты в XPath 2.0 для обработки ваших данных (регулярное выражение, перевод...), см.: http://www.w3.org/TR/xpath-functions/#string-functions.

person Vincent Biragnet    schedule 08.12.2011