2015-01-28 4 views
2

В документе XML я намерен вставлять элементы между двумя самозакрывающимися элементами. Рассмотрим следующий пример:Вставить элемент между самозакрывающимися элементами

<body> 
    <p>Lorem ipsum dolor sit amet, 
    <lb/>consectetur adipisici elit, 
    <lb/>sed eiusmod tempor incidunt 
    <lb/>ut labore et dolore magna aliqua. 
    </p> 
    <p>Ut enim ad minim veniam, 
    <lb/>quis nostrud exercitation ullamco 
    <lb/>laboris nisi ut aliquid 
    <lb/>ex ea commodi consequat. 
    </p> 
</body> 

Таким образом, существуют такие конструкции, как параграфы (p) и разрывы строк (фунты). Моя цель состоит в том, чтобы поместить линии в элементы. Поэтому я хотел бы получить следующий результат преобразования (или аналогичный):

<body> 
    <p> 
    <l>Lorem ipsum dolor sit amet,</l> 
    <l>consectetur adipisici elit,</l> 
    <l>sed eiusmod tempor incidunt</l> 
    <l>ut labore et dolore magna aliqua.</l> 
    </p> 
    <p> 
    <l>Ut enim ad minim veniam,</l> 
    <l>quis nostrud exercitation ullamco</l> 
    <l>laboris nisi ut aliquid</l> 
    <l>ex ea commodi consequat.</l> 
    </p> 
</body> 

Возможно ли это с помощью XSLT? Похоже, что это не типичное приложение, поскольку я еще не нашел подхода. Я был бы признателен за любую помощь.

EDIT: А вот более сложный вариант задачи, который добавляет: (1) выделены, перекрывая проходы (Hi) и перекрывающийся элемент (2) «Выбор», из которых только «СИК» элемент должен быть сохранен.

<body> 
    <p>Lorem ipsum dolor sit amet, 
    <lb/>consectetur adipisici elit, 
    <lb/>sed eiusmod tempor <hi>incidunt 
    <lb/>ut labore</hi> et dolore magna aliqua. 
    </p> 
    <p>Ut enim ad minim <choice> 
     <sic>venima, <lb/>quis noster</sic> 
     <corr>veniam, quis nostrud</corr> 
    </choice> exercitation ullamco 
    <lb/>laboris nisi ut aliquid 
    <lb/>ex ea commodi consequat. 
    </p> 
</body> 

Желаемый результат будет, например, с (1) номера строк и (2) @cont атрибут, который указывает продолжение расщепленным элемента.

<body> 
    <p> 
    <l n="1">Lorem ipsum dolor sit amet,</l> 
    <l n="2">consectetur adipisici elit,</l> 
    <l n="3">sed eiusmod tempor <hi cont="true">incidunt</hi></l> 
    <l n="4"><hi cont="false">ut labore</hi> et dolore magna aliqua.</l> 
    </p> 
    <p> 
    <l n="5">Ut enim ad minim <sic cont="true">venima,</sic></l> 
    <l n="6"><sic cont="false">quis noster</sic> exercitation ullamco</l> 
    <l n="7">laboris nisi ut aliquid</l> 
    <l n="8">ex ea commodi consequat.</l> 
    </p> 
</body> 

Это практически охватывает наихудшие случаи, с которыми я столкнулся. Я ценю вашу помощь!

+0

Вы можете использовать XSLT 2.0 как Saxon 9 или XmlPrime?В этом случае это задание для ' '. –

+0

Да, я использую Oxygen, поэтому есть некоторые варианты в отношении XSLT-процессоров. –

ответ

2

Если между строками всегда есть элемент lb, будет выполняться следующее: текстовое содержимое, разделенное дочерними элементами, попадает в отдельные текстовые узлы.

таблицы стилей XSLT

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="body"> 
     <xsl:copy> 
      <xsl:apply-templates/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="p"> 
     <xsl:copy> 
      <xsl:for-each select="text()"> 
       <l> 
        <xsl:value-of select="normalize-space(.)"/> 
       </l> 
      </xsl:for-each> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

XML-выход

<?xml version="1.0" encoding="UTF-8"?> 
<body> 
    <p> 
     <l>Lorem ipsum dolor sit amet,</l> 
     <l>consectetur adipisici elit,</l> 
     <l>sed eiusmod tempor incidunt</l> 
     <l>ut labore et dolore magna aliqua.</l> 
    </p> 
    <p> 
     <l>Ut enim ad minim veniam,</l> 
     <l>quis nostrud exercitation ullamco</l> 
     <l>laboris nisi ut aliquid</l> 
     <l>ex ea commodi consequat.</l> 
    </p> 
</body> 
+0

Хорошо! Это указывает на правильное направление. На самом деле мой пример очень упрощен, поэтому, возможно, я добавлю еще один пример позже. –

+0

@friedemann_bach Для ваших будущих вопросов, пожалуйста, убедитесь, что входной XML, который вы показываете, точно отражает уровень сложности, присутствующий в ваших фактических данных. В противном случае мы обязаны дать ответ, который не поможет. –

+0

@friedemann_bach Итак, как мы можем продолжить ваш вопрос? Измените свой вопрос, чтобы включить расширенный образец вашего входного XML, как вы сами предложили. –

3

А вот более сложный вариант задачи, который добавляет: (1) выделены, перекрывая проходы (hi) и (2) перекрывающийся «выбор» элемент, из которого только элемент «sic» n необходимо сохранить.

Ну, это интересно - хотя это может быть слишком много для одного вопроса SO. В любом случае, я не мог найти способ сделать все это сразу. Следующая таблица стилей использует два прохода, чтобы вернуть результат, который почти то, что вы просили:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:variable name="first-pass"> 
    <xsl:apply-templates select="/*" mode="first-pass"/> 
</xsl:variable> 

<!-- identity transform --> 
<xsl:template match="@*|node()" mode="#all"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()" mode="#current"/> 
    </xsl:copy> 
</xsl:template> 

<!-- FIRST-PASS TEMPLATES --> 

<!-- remove choice wrapper, preserve only sic content --> 
<xsl:template match="choice" mode="first-pass"> 
    <xsl:apply-templates select="sic" mode="first-pass"/> 
</xsl:template> 

<!-- split hi and sic accross lb --> 
<xsl:template match="hi | sic" mode="first-pass"> 
    <xsl:variable name="elem-name" select="local-name()" /> 
    <xsl:for-each-group select="text()" group-by="generate-id(preceding-sibling::lb[1])"> 
     <xsl:element name="{$elem-name}"> 
     <xsl:attribute name="cont" select="position()!=last()"/> 
      <xsl:apply-templates select="current-group()" mode="first-pass"/> 
     </xsl:element> 
     <xsl:if test="position()!=last()"> 
      <lb/> 
     </xsl:if> 
    </xsl:for-each-group> 
</xsl:template> 

<!-- OUTPUT --> 

<xsl:template match="/"> 
    <xsl:apply-templates select="$first-pass/*"/> 
</xsl:template> 

<!-- create a line element for each group separated by lb --> 
<xsl:template match="*[lb]"> 
    <xsl:copy> 
     <xsl:for-each-group select="node()" group-ending-with="lb"> 
      <l n="{position()}"> 
       <xsl:apply-templates select="current-group()"/> 
      </l> 
     </xsl:for-each-group> 
    </xsl:copy> 
</xsl:template> 

<!-- suppress lb --> 
<xsl:template match="lb"/> 

</xsl:stylesheet> 

Результат:

<?xml version="1.0" encoding="UTF-8"?> 
<body> 
    <p> 
     <l n="1">Lorem ipsum dolor sit amet, 
    </l> 
     <l n="2">consectetur adipisici elit, 
    </l> 
     <l n="3">sed eiusmod tempor <hi cont="true">incidunt 
    </hi> 
     </l> 
     <l n="4"> 
     <hi cont="false">ut labore</hi> et dolore magna aliqua. 
    </l> 
    </p> 
    <p> 
     <l n="1">Ut enim ad minim <sic cont="true">venima, </sic> 
     </l> 
     <l n="2"> 
     <sic cont="false">quis noster</sic> exercitation ullamco 
    </l> 
     <l n="3">laboris nisi ut aliquid 
    </l> 
     <l n="4">ex ea commodi consequat. 
    </l> 
    </p> 
</body> 
+0

Отлично, большое спасибо. Это работает лучше, чем я ожидал. Тем не менее, я дал «ответ» на @ mathias-müller, потому что он полностью ответил на мой первоначальный вопрос. Возможно, в следующий раз мне придется разделить такие вопросы по двум вопросам. –

+1

Если во время первого прохода вы добавляете в конце каждого p, вы можете иметь правильный счет строки, используя {count (current-group() [last()]/before :: lb) + 1} instad of {должность()} – lfurini

Смежные вопросы