Задать вопрос
@drumminman
Tehwriter, mountain biker, trailbuilder

Варианты поиска текстовой ноды с вложенными inline-тегами?

Всем доброго времени суток.
В общем, ситуация такая. Имеются исходники документации в DocBook XML 4.5, которые я сейчас переформатирую в DocBook 5.
И в старых исходниках периодически встречаются места, в которых текстовые ноды лежат в качестве прямых потомков узлов, которые в DocBook 5 уже не предполагают возможности такого расположения. Более того, при этом эта текстовая нода может еще содержать один или несколько inline-тегов.
К примеру:
<entry>
   <para>какой то параграф</para>
  <itemizedlist/>
   просто текст с каким то <sgmltag>инлайн-тегом</sgmltag>
</entry>

Соответственно, при переводе из старого формата в новый (есть там один скриптик), оксиген начинает сильно ругаться на подобные вещи.
Я пытаюсь отловить подобные ноды, но что то как то пока безуспешно
Текущий шаблон следующий (он еще заодно все потомки , которые не в параграфах, перемещает в para):
<xsl:template match="*[parent::entry]">        
        <xsl:choose>
           <xsl:when test="self::para">
               <xsl:copy>                
                   <xsl:copy-of select="@*"/>
                   <xsl:apply-templates/>                
               </xsl:copy>
           </xsl:when>
           <xsl:otherwise>
                       <para>
                           <xsl:copy>                
                               <xsl:copy-of select="@*"/>
                               <xsl:apply-templates/>                
                           </xsl:copy> 
                       </para>
           </xsl:otherwise>
       </xsl:choose> 
    </xsl:template>  

    <xsl:template match="text()[parent::entry]">
        <xsl:variable name="varTest">
            <xsl:value-of select="normalize-space(.)"/>
        </xsl:variable>
        <xsl:if test="$varTest != ''">
            <para>
                <xsl:copy-of select="normalize-space(.)"/>            
            </para>
        </xsl:if>        
    </xsl:template>

По итогу применения, эти два шаблона на выходе дадут XML вида:
<entry>
   <para>какой то параграф</para>
   <para><itemizedlist/></para>
   <para>просто текст с каким то </para><para><sgmltag>инлайн-тегом</sgmltag></para>
</entry>


Конечный вывод не радует, надо как то перенести всю строку вместе с sgmltag внутрь одного para, а как получить именно всю текстовую ноду + инлайн тег внутри нее, не понятно.

Руками просто это все править я умахаюсь, исходников сотни файлов, хотелось бы как то автоматизировать..
  • Вопрос задан
  • 61 просмотр
Подписаться 5 Средний 1 комментарий
Решения вопроса 1
@drumminman Автор вопроса
Tehwriter, mountain biker, trailbuilder
В общем, спустя два года, на помощь пришел китайский ИИ. Совместными усилиями был рожден следующий способ:
<xsl:template match="entry">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:for-each-group select="node()" 
            group-adjacent="boolean(
                self::para | 
                self::itemizedlist | 
                self::orderedlist | 
                self::variablelist |
                self::table |
                self::informaltable
            )">
            
            <xsl:choose>
                <!-- Группа блочных элементов -->
                <xsl:when test="current-grouping-key()">
                    <xsl:apply-templates select="current-group()"/>
                </xsl:when>
                
                <!-- Группа текста/инлайн-элементов - оборачиваем только если есть значимый контент -->
                <xsl:otherwise>
                    <xsl:variable name="group-content">
                        <xsl:apply-templates select="current-group()"/>
                    </xsl:variable>
                    
                    <xsl:if test="normalize-space($group-content) != ''">
                        <para>
                            <xsl:copy-of select="$group-content"/>
                        </para>
                    </xsl:if>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

где мы используем инструкции и функции xsl 2.0 for-each-group и group-content() для группировки. Т.к. у нас есть четкое деление на блочные элементы, и все остальное, то отделяем блочные от неблочных, и все непустые неблочные (к которым и относится голый текст либо инлайн-элементы) оборачиваем в нужный нам блочный элемент. Вроде работает.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
dimonchik2013
@dimonchik2013
non progredi est regredi
Ваша проблема - в невладении инструментом: как знающему Питон поверхностно (ну или не поверхностно), мне искренне непонятно, как с структурированным текстовым форматом можно не мочь что-то сделать?

Вы упоминаете Оксиген, видимо, это он
https://www.oxygenxml.com/xml_editor/xpath.html

ну, пробуйте им - Xpath в помощь
https://stackoverflow.com/questions/27017302/xpath...

для всего остального - Python + lxml
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы