XML в WordML с использованием XSLT 1.0 - замените HTML-теги в содержимом XML на теги форматирования WordML - PullRequest
1 голос
/ 24 октября 2008

Я создаю документ WordML из файла xml, элементы которого иногда содержат текст в формате html.

<w:p>
  <w:r>
    <w:t> html formatted content is in here taken from xml file! </w:t>
  </w:r>
</w:p>

Так настроены мои шаблоны. У меня есть рекурсивная функция шаблона вызова, которая выполняет замену текста на исходный XML-контент. Когда он сталкивается с тегом "<b>", я вывожу строку в CDATA, содержащую "</w:t></w:r><w:r><w:rPr><w:b/></w:rPr><w:t>", чтобы закрыть текущий цикл и запустить новый цикл с включенным форматированием жирным шрифтом. когда он попадает в тег "</b>", он заменяет его следующей строкой CDATA "</w:t></w:r><w:r><w:t>".

Что я хотел бы сделать, так это использовать XSL, чтобы закрыть тег запуска и начать новый запуск без использования вставок строки CDATA. Это возможно?

Ответы [ 4 ]

3 голосов
/ 30 октября 2008

Работать с WordML сложно. Одним из советов при преобразовании произвольного XML в WordML с использованием XSLT является не беспокоиться о выполнении текста при обработке блоков, а вместо этого создать шаблон, который напрямую соответствует узлам text (), и создать текстовые прогоны там. Оказывается, Word не заботится о вложенности текста, что значительно облегчает решение проблемы.

   <xsl:template match="text()" priority="1">
         <w:r>
            <w:t>
               <xsl:value-of select="."/>
            </w:t>
         </w:r> 
   </xsl:template>

   <xsl:template match="@*|node()">
       <xsl:apply-templates select="@*|node()"/>
   </xsl:template>

   <xsl:template match="para">
      <w:p>
         <xsl:apply-templates select="text() | *" />
      </w:p>
   </xsl:template>

   <xsl:template match="b">
      <w:r>
         <w:rPr>
            <w:b />
         </w:rPr>
         <w:t><xsl:apply-templates /></w:t>
      </w:r>
   </xsl:template>

Это позволяет избежать плохой техники XSLT вставки тегов непосредственно в качестве экранированного текста. Вы получите жирный тэг в виде вложенного текста, но, как я уже сказал, Word все равно. Если вы используете эту технику, вам нужно быть осторожным, чтобы не применять шаблоны к пустому пространству между абзацами, так как это вызовет текстовый шаблон и создаст вне контекста.

0 голосов
/ 27 июля 2009

Чтобы полностью закончить HTML> WordML, я рекомендую эту отредактированную версию вашего кода:

<xsl:template match="Body"><xsl:apply-templates select="p"/></xsl:template>

<xsl:template match="text()" priority="1"><w:r><w:t><xsl:value-of select="."/></w:t></w:r></xsl:template>

<xsl:template match="@*|node()"><xsl:apply-templates select="@*|node()"/></xsl:template>

<xsl:template match="p"><w:p><xsl:apply-templates select="text() | *" /></w:p></xsl:template>

<xsl:template match="b"><w:r><w:rPr><w:b /></w:rPr><xsl:apply-templates /></w:r></xsl:template>
<xsl:template match="i"><w:r><w:rPr><w:i /></w:rPr><xsl:apply-templates /></w:r></xsl:template>
<xsl:template match="u"><w:r><w:rPr><w:u w:val="single" /></w:rPr><xsl:apply-templates /></w:r></xsl:template>

предположим, что ваш HTML-код где-то в XMl обернут в тег

0 голосов
/ 27 октября 2008

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

Пример ввода:

<text>
  <para>
    Test for paragraph 1
  </para>
  <para>
    Test for <b>paragraph 2</b>
  </para>
</text>

Transform:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:w="http://foo">
<xsl:template match="/">
  <w:p>
    <w:r>
      <xsl:apply-templates/>
    </w:r>     
  </w:p>
</xsl:template>
  <xsl:template match="para">
    <w:t>
      <xsl:apply-templates/>
    </w:t>
  </xsl:template>

  <xsl:template match="b">
    <w:rPr>
      <w:b/>
    </w:rPr>
      <xsl:value-of select="."/>
  </xsl:template>
</xsl:stylesheet> 

Результат:

<w:p xmlns:w="http://foo">
  <w:r>
    <w:t>
      Test for paragraph 1
    </w:t>
    <w:t>
      Test for <w:rPr><w:b /></w:rPr>paragraph 2
    </w:t>
  </w:r>
</w:p>
0 голосов
/ 27 октября 2008

Скорее всего, я могу помочь вам, если б я понял вашу проблему ... HTML находится в разделе CDATA или он анализируется как часть входного документа (и, следовательно, правильно сформированного XML)? Поскольку вы говорите о «замене текста», я предполагаю, что вы рассматриваете «контент, отформатированный в html», как одну строку (CDATA), и поэтому для выполнения замены строки требуется рекурсивная функция шаблона вызова. Единственный способ использовать шаблон сопоставления XSL для выполнения того, что вы делаете сейчас, - это сделать html частью анализируемого документа (вашего входного документа). В таком случае вы можете просто сопоставить тег b и заменить его соответствующим выводом (опять же: это предполагает, что он всегда может быть проанализирован как действительный XML). Ваша проблема теперь изменилась ... поскольку (если я правильно понял вашу проблему) вы пытаетесь закрыть элементы w:t и w:r, а затем снова открыть их ... это сложно, потому что это ( как вы, вероятно, подозреваете) очень сложно сделать это красиво в XSLT (вы не можете просто создать элемент в шаблоне A и затем закрыть его в шаблоне B). Вы должны начать возиться с неэкранированным выводом и т. Д., Чтобы это произошло. Теперь я сделал много предположений, но вот небольшой пример, который поможет вам на вашем пути:

Input.xml

<doc xmlns:w="urn:schemas-microsoft-com:office:word">
<w:p>
  <w:r>
    <w:t>before<b>bold</b>after</w:t>
  </w:r>
</w:p>
</doc>

convert_html.xsl

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="/doc/w:p/w:r/w:t//b">
  <xsl:value-of select="'&lt;/w:t>&lt;/w:r>&lt;w:r>&lt;w:rPr>&lt;w:b/>&lt;/w:rPr>&lt;w:t>'" disable-output-escaping="yes" />
  <xsl:apply-templates select="@*|node()"/>
  <xsl:value-of select="'&lt;/w:t>&lt;/w:r>&lt;w:r>&lt;w:t>'" disable-output-escaping="yes" />
</xsl:template>

Сейчас работает

xalan input.xml convert_html.xsl

производит

<?xml version="1.0" encoding="UTF-8"?><doc xmlns:w="urn:schemas-microsoft-com:office:word">
<w:p>
  <w:r>
    <w:t>before</w:t></w:r><w:r><w:rPr><w:b/></w:rPr><w:t>bold</w:t></w:r><w:r><w:t>after</w:t>
  </w:r>
</w:p>
</doc>

что я думаю, это то, что вы хотели.

Надеюсь, это вам чем-нибудь поможет.

...