Интеллектуальный разрыв строки: довольно печатный вывод файла makefile через XSLT - PullRequest
2 голосов
/ 14 февраля 2011

Мне нужно распечатать некоторые выходные данные make через XSLT (xsltproc), уделяя особое внимание удобочитаемости вызовов gcc (поскольку они являются наиболее распространенными и важными строками в указанном выводе).

Ситуация: у меня в исходном XML-файле много длинных <message>gcc -Wall ...</message> узлов, одна строка необработанного файла makefile на каждый узел <message>. Результатом моего листа XSLT будет HTML, в котором содержимое узлов <message> построчно помещается в среду <pre>. Я хотел бы разбить строку предпочтительно в любом случае "-" (т. Е. В начале параметра командной строки) - если он не найден, в некоторых символах (например, -/.:;=), то в любом пробеле ; разрыв строки в середине строки должен быть последним средством. Я установил глобальную переменную $break-at, обозначающую максимальное количество символов в строке.

Проблема: я не могу использовать функции XSLT 2.0 на xsltproc (или я не нашел никакой информации относительно их импорта). Поэтому я застрял с substring-before(), substring-after(), contains(), substring(), string-length() (к сожалению, tokenize() недоступен). Кажется, я не нахожу способ разорвать строку при последнем появлении пробела (или любого токена) прямо перед $break-at.

Это выдержка из исходного XML:

<message priority="info"><![CDATA[/usr/bin/moc -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. main.cpp -o main.moc]]></message>
<message priority="info"><![CDATA[/tmp/Akut/work/1296322206337_e01c972b8fe9b866aded56ff5dde35c3/AspectC++/bin/linux-release/ag++ -p /tmp/Akut/work/1296322206337_e01c972b8fe9b866aded56ff5dde35c3/1297456240104_09fad65d9a05790369dd919025284109_20110211213211/qt-examples --Xcompiler -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -o main.o main.cpp]]></message>
<message priority="info"><![CDATA[/tmp/main.cpp_agxx_c5k6Om: In destructor 'AC::ResultBuffer<T>::~ResultBuffer() [with T = QRectF]':]]></message>
<message priority="info"><![CDATA[/tmp/main.cpp_agxx_c5k6Om:216:33:   instantiated from here]]></message>
<message priority="info"><![CDATA[/tmp/main.cpp_agxx_c5k6Om:26:24: warning: dereferencing type-punned pointer will break strict-aliasing rules]]></message>

Это вызывающий XSLT-код, вызывающий шаблон break-string в каждой строке вывода:

<code><pre>
  <xsl:for-each select="message">
    <xsl:call-template name="break-string">
      <xsl:with-param name="string" select="./text()"/>      
    </xsl:call-template>
  </xsl:for-each>

Пока это мой break-string шаблон - пока что неудовлетворительно!

<xsl:template name="break-string">
  <xsl:param name="string" />
  <xsl:choose>
    <xsl:when test="string-length($string) &lt;= $break-at">
      <xsl:value-of select="$string"/><xsl:text>&#xa;</xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:choose>
        <xsl:when test="contains($string, ' -')">
          <xsl:variable name="out" select="substring-before($string, ' -')"/>
          <xsl:choose>
            <xsl:when test="string-length($out) &lt;= $break-at">
               <xsl:value-of select="$out"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:call-template name="break-string">
                <xsl:with-param name="string"
                                select="$out" />
              </xsl:call-template>
            </xsl:otherwise>
          </xsl:choose>
          <xsl:text>&#xa;</xsl:text>
          <span class="indent"><xsl:text><![CDATA[  ]]></xsl:text></span><xsl:text>-</xsl:text>
          <xsl:call-template name="break-string">
            <xsl:with-param name="string"
                            select="substring-after($string, ' -')" />
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="substring($string, 1, $break-at)" /><xsl:text>&#xa;</xsl:text>
          <span class="indent"><xsl:text><![CDATA[  ]]></xsl:text></span>
          <xsl:call-template name="break-string">
            <xsl:with-param name="string"
                            select="substring($string, $break-at + 1)" />
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Какой самый элегантный способ разорвать эти строки?

Ответы [ 2 ]

1 голос
/ 16 февраля 2011

Добавление своего без расширений:

<code><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="pSeparators" select="'&#xD;&#xA;&#x9;&#x20;-/.:;='"/>
    <xsl:param name="pMaxLength" select="64"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="message">
        <pre>
            <xsl:call-template name="tokenize"/>
        
</ XSL: шаблон> = $ vLength"> </ XSL: вызов-шаблон> </ XSL: когда> $ pMaxLength "> </ XSL: вызов-шаблон> </ XSL: когда> </ XSL: вызов-шаблон> </ XSL: в противном случае> </ XSL: выберите> </ XSL: если> </ XSL: шаблон> </ XSL: таблицы стилей>

С этим входом:

<t>
    <message priority="info"><![CDATA[/usr/bin/moc -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. main.cpp -o main.moc]]></message>
    <message priority="info"><![CDATA[/tmp/Akut/work/1296322206337_e01c972b8fe9b866aded56ff5dde35c3/AspectC++/bin/linux-release/ag++ -p /tmp/Akut/work/1296322206337_e01c972b8fe9b866aded56ff5dde35c3/1297456240104_09fad65d9a05790369dd919025284109_20110211213211/qt-examples --Xcompiler -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -o main.o main.cpp]]></message>
    <message priority="info"><![CDATA[/tmp/main.cpp_agxx_c5k6Om: In destructor 'AC::ResultBuffer<T>::~ResultBuffer() [with T = QRectF]':]]></message>
    <message priority="info"><![CDATA[/tmp/main.cpp_agxx_c5k6Om:216:33:   instantiated from here]]></message>
    <message priority="info"><![CDATA[/tmp/main.cpp_agxx_c5k6Om:26:24: warning: dereferencing type-punned pointer will break strict-aliasing rules]]></message>
</t>

Выход:

<code><t><pre>/usr/bin/moc -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB 
-DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr
/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 
-I. main.cpp -o main.moc
/tmp/Akut/work/1296322206337_e01c972b8fe9b866aded56ff5dde35c3
/AspectC++/bin/linux-release/ag++ -p /tmp/Akut/work
/1296322206337_e01c972b8fe9b866aded56ff5dde35c3
/1297456240104_09fad65d9a05790369dd919025284109_20110211213211
/qt-examples --Xcompiler -c -pipe -O2 -Wall -W -D_REENTRANT 
-DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr
/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I
/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -o main.o main.cpp
/tmp/main.cpp_agxx_c5k6Om: In destructor 'AC::ResultBuffer&lt;T&gt;:
:~ResultBuffer() [with T = QRectF]'
/tmp/main.cpp_agxx_c5k6Om:216:33:   instantiated from here
/tmp/main.cpp_agxx_c5k6Om:26:24: warning: dereferencing type
-punned pointer will break strict-aliasing rules

Оказано:

/usr/bin/moc -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB 
-DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr
/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 
-I. main.cpp -o main.moc
/tmp/Akut/work/1296322206337_e01c972b8fe9b866aded56ff5dde35c3
/AspectC++/bin/linux-release/ag++ -p /tmp/Akut/work
/1296322206337_e01c972b8fe9b866aded56ff5dde35c3
/1297456240104_09fad65d9a05790369dd919025284109_20110211213211
/qt-examples --Xcompiler -c -pipe -O2 -Wall -W -D_REENTRANT 
-DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr
/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I
/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -o main.o main.cpp
/tmp/main.cpp_agxx_c5k6Om: In destructor 'AC::ResultBuffer<T>:
:~ResultBuffer() [with T = QRectF]'
/tmp/main.cpp_agxx_c5k6Om:216:33:   instantiated from here
/tmp/main.cpp_agxx_c5k6Om:26:24: warning: dereferencing type
-punned pointer will break strict-aliasing rules

Примечание : Основой является мошенничество с несколькими разделителями, «подхватывающее» разделитель (поскольку похоже, что вы хотите сохранить разделитель со следующим элементом).Я не уделил слишком много времени, но логика взлома может быть еще более упрощена.Теперь есть три случая: элемент помещается в текущую строку, элемент не помещается в полную строку (разбить элемент), элемент не помещается в текущую строку, но он помещается в новую строку (новая строка, не разбивать элемент).

0 голосов
/ 14 февраля 2011

Вы можете использовать существующий шаблон str-split-to-lines из FXSL :

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
xmlns:str-split2lines-func="f:str-split2lines-func"
exclude-result-prefixes="xsl ext str-split2lines-func"
>


   <xsl:import href="dvc-str-foldl.xsl"/>

   <str-split2lines-func:str-split2lines-func/>

   <xsl:output indent="yes" omit-xml-declaration="yes"/>

    <xsl:template match="/">
      <xsl:call-template name="str-split-to-lines">
        <xsl:with-param name="pStr" select="/*"/>
        <xsl:with-param name="pLineLength" select="64"/>
        <xsl:with-param name="pDelimiters" select="' &#9;&#10;&#13;'"/>
      </xsl:call-template>
    </xsl:template>

    <xsl:template name="str-split-to-lines">
      <xsl:param name="pStr"/>
      <xsl:param name="pLineLength" select="60"/>
      <xsl:param name="pDelimiters" select="' &#9;&#10;&#13;'"/>

      <xsl:variable name="vsplit2linesFun"
                    select="document('')/*/str-split2lines-func:*[1]"/>

      <xsl:variable name="vrtfParams">
       <delimiters><xsl:value-of select="$pDelimiters"/></delimiters>
       <lineLength><xsl:copy-of select="$pLineLength"/></lineLength>
      </xsl:variable>

      <xsl:variable name="vResult">
          <xsl:call-template name="dvc-str-foldl">
            <xsl:with-param name="pFunc" select="$vsplit2linesFun"/>
            <xsl:with-param name="pStr" select="$pStr"/>
            <xsl:with-param name="pA0" select="ext:node-set($vrtfParams)"/>
          </xsl:call-template>
      </xsl:variable>

      <xsl:for-each select="ext:node-set($vResult)/line">
        <xsl:for-each select="word">
          <xsl:value-of select="concat(., ' ')"/>
        </xsl:for-each>
        <xsl:value-of select="'&#xA;'"/>
      </xsl:for-each>
    </xsl:template>

    <xsl:template match="str-split2lines-func:*">
      <xsl:param name="arg1" select="/.."/>
      <xsl:param name="arg2"/>

      <xsl:copy-of select="$arg1/*[position() &lt; 3]"/>
      <xsl:copy-of select="$arg1/line[position() != last()]"/>

      <xsl:choose>
        <xsl:when test="contains($arg1/*[1], $arg2)">
          <xsl:if test="string($arg1/word)">
             <xsl:call-template name="fillLine">
               <xsl:with-param name="pLine" select="$arg1/line[last()]"/>
               <xsl:with-param name="pWord" select="$arg1/word"/>
               <xsl:with-param name="pLineLength" select="$arg1/*[2]"/>
             </xsl:call-template>
          </xsl:if>
        </xsl:when>
        <xsl:otherwise>
          <xsl:copy-of select="$arg1/line[last()]"/>
          <word><xsl:value-of select="concat($arg1/word, $arg2)"/></word>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>

      <!-- Test if the new word fits into the last line -->
    <xsl:template name="fillLine">
      <xsl:param name="pLine" select="/.."/>
      <xsl:param name="pWord" select="/.."/>
      <xsl:param name="pLineLength" />

      <xsl:variable name="vnWordsInLine" select="count($pLine/word)"/>
      <xsl:variable name="vLineLength" 
       select="string-length($pLine) + $vnWordsInLine"/>
      <xsl:choose>
        <xsl:when test="not($vLineLength + string-length($pWord) 
                           > 
                            $pLineLength)">
          <line>
            <xsl:copy-of select="$pLine/*"/>
            <xsl:copy-of select="$pWord"/>
          </line>
        </xsl:when>
        <xsl:otherwise>
          <xsl:copy-of select="$pLine"/>
          <line>
            <xsl:copy-of select="$pWord"/>
          </line>
          <word/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>

</xsl:stylesheet>

, когда это преобразование применяется к этому документу XML (первый элемент вашего XML):

<message priority="info"><![CDATA[/usr/bin/moc -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. main.cpp -o main.moc]]></message>

желаемый, правильный результат (разбит на строки с максимальной длиной 64):

/usr/bin/moc -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB 
-DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. 
-I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui 
-I/usr/include/qt4 -I. main.cpp -o 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...