xslt: создать новый узел из смешанного содержимого в родительском элементе - PullRequest
0 голосов
/ 10 сентября 2010

Я пытаюсь написать шаблон, который будет брать смесь текстовых узлов и элементов внутри родительского элемента и создавать новый узел.Я много искал и не смог найти то, что искал ... так что, надеюсь, я не задаю основной вопрос.

Вот пример xml, который я хочу преобразовать:

<?xml version="1.0"?>
<root>
 <para>Here is some text that will ask users to enter a <rule-line/> [<emph type="it">date</emph>], and maybe their <rule-line/> [<emph type="it">name</emph>]. The text could come in different [<emph type="it">order</emph>] <rule-line/>, and their could be any number of instances.</para>

</root>

Я хочу сгруппировать текст в скобках и правило в новый элемент, например:

<entry>[<emph type"it">date</emph>]</entry>

У меня есть шаблон, который может идентифицировать текст, который я хочу изменить, и я могу изменить его, но я не знаю, как добавить нужный текст в дерево результатов и пропустить старый текст.

Вот соответствующие шаблоны:

<xsl:template match="para">
 <xsl:for-each select="* | text()">
  <xsl:choose>

   <xsl:when test="self::rule-line and following-sibling::node()[1][starts-with(., ' [')] and string(node-name(following-sibling::node()[2])) = 'emph' and following-sibling::node()[3][starts-with(., ']')]">
    <xsl:comment>made match</xsl:comment>
    <xsl:call-template name="codeEntry">
     <xsl:with-param name="rule" select="."/>
     <xsl:with-param name="openBracket" select="following-sibling::node()[1]"/>
     <xsl:with-param name="emphTag" select="following-sibling::node()[2]"/>
     <xsl:with-param name="closeBracketString" select="following-sibling::node()[3]"/>
    </xsl:call-template>
   </xsl:when>
   <xsl:otherwise>
    <xsl:copy-of select="."/>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:for-each>

</xsl:template>


<xsl:template name="codeEntry">
<xsl:param name="rule"/>
<xsl:param name="openBracket"/>
<xsl:param name="emphTag"/>
<xsl:param name="closeBracketString"/>
<entry>
<xsl:copy-of select="$openBracket"/>
<xsl:copy-of select="$emphTag"/>
<xsl:text>] </xsl:text>
</entry>
<xsl:value-of select="substring-after($closeBracketString, ']')"/>

</xsl:template>

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

Я думаю, что создание переменной, которая говорит шаблону игнорировать узел, - это путь ...но я немного запутался в неизменяемых переменных и их области видимости ...

Я также пытался придумать, как я могу попытаться сделать это рекурсивно ... но это потребовало бы добавления начального тегав одной точке, конечный тег в другой или нет тега, если обрабатываемый узел находится в середине последовательности ... и я знаю, что это может стать странным в xslt.

Кто-нибудь сталкивался с такой ситуацией раньше?спасибо, Джейсон

любые идеи

1 Ответ

1 голос
/ 10 сентября 2010

Просто для удовольствия (какой беспорядок в схеме!) Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="rule-line"/>
    <xsl:template match="emph">
        <entry>
            <xsl:text>[</xsl:text>
            <xsl:call-template name="identity"/>
            <xsl:text>]</xsl:text>
        </entry>
    </xsl:template>
    <xsl:template match="text()[normalize-space()='[']
                               [following-sibling::*[1][self::emph]] |
                         text()[normalize-space()=']']
                               [preceding-sibling::*[1][self::emph]]"
                  priority="1"/>
    <xsl:template match="text()[starts-with(normalize-space(),']')]
                               [preceding-sibling::*[1][self::emph]]">
        <xsl:value-of select="substring-after(.,']')"/>
    </xsl:template>
    <xsl:template match="text()[substring(normalize-space(),
                                          string-length(normalize-space()),
                                          1) = '[']
                               [following-sibling::*[1][self::emph]]">
        <xsl:call-template name="crop-both">
            <xsl:with-param name="pString" select="concat(']',.)"/>
        </xsl:call-template>
    </xsl:template>
    <xsl:template match="text()[starts-with(normalize-space(),']')]
                               [substring(normalize-space(),
                                          string-length(normalize-space()),
                                          1) = '[']
                               [preceding-sibling::*[1][self::emph]]
                               [following-sibling::*[1][self::emph]]"
                  priority="1" name="crop-both">
        <xsl:param name="pString" select="."/>
        <xsl:variable name="vReverse">
            <xsl:call-template name="reverse">
                <xsl:with-param name="pString" 
                                select="substring-after(.,']')"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:call-template name="reverse">
            <xsl:with-param name="pString"
                            select="substring-after($vReverse,'[')"/>
        </xsl:call-template>
    </xsl:template>
    <xsl:template name="reverse">
        <xsl:param name="pString"/>
        <xsl:if test="$pString!=''">
            <xsl:call-template name="reverse">
                <xsl:with-param name="pString"
                                select="substring($pString,2)"/>
            </xsl:call-template>
            <xsl:value-of select="substring($pString,1,1)"/>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Выход:

<root>
<para>Here is some text that will ask users to enter a <entry>[<emph type="it">date</emph>]</entry>, and maybe their <entry>[<emph type="it">name</emph>]</entry>. The text could come in different <entry>[<emph type="it">order</emph>]</entry>, and their could be any number of instances.</para>
</root>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...