XSLT: переместить одноуровневый текстовый узел в выбранный узел для исправления XLIFF

После нескольких часов изучения XSLT я признаю поражение! Мне нужно исправить большое количество файлов перевода .xlf XLIFF, которые были возвращены нам искаженными из безымянного инструмента перевода. В идеале я бы применил к ним XSL-преобразование с помощью пакетного инструмента.

Ниже приведен фрагмент одного из файлов XLIFF:

<body>
    <trans-unit id="1" phase-name="pretrans" restype="x-h3">
        <source>Adding, Deleting or Modifying Notes in the Call Description</source>
        <seg-source>Adding, Deleting or Modifying Notes in the Call Description</seg-source>
        <target state="final">Добавление, удаление и изменение примечаний в описании звонка</target>
    </trans-unit>
    <trans-unit id="2" phase-name="pretrans" restype="x-p">
        <source>Description of Fields on RHS</source>
        <seg-source>Description of Fields on RHS</seg-source>
        <target state="final">Поле описания в правой части</target>
    </trans-unit>
    <trans-unit id="3" phase-name="pretrans" restype="x-p">
        <source>You can add descriptive text notes to a call recording, if you have the appropriate privileges to do so. These notes are visible to all users who have access to the call recording. It is recommended that each user add their initials to the notes to avoid potential confusion.</source>
        <seg-source>
            <mrk mtype="seg" mid="1">You can add descriptive text notes to a call recording, if you have the appropriate privileges to do so.</mrk>
            <mrk mtype="seg" mid="2">These notes are visible to all users who have access to the call recording.</mrk>
            <mrk mtype="seg" mid="3">It is recommended that each user add their initials to the notes to avoid potential confusion.</mrk>
        </seg-source>
        <target state="final">
          <mrk mtype="seg" mid="1" /><ph ctype="" id="1">&lt;MadCap:variable name="zoom_userdocs_variables.var_product_name" xmlns:MadCap="http://www.madcapsoftware.com/Schemas/MadCap.xsd" /&gt;</ph> позволяет находить телефонные взаимодействия, содержащие или не содержащие определенные фразы.
          <mrk mtype="seg" mid="2" />Каждая речевая метка содержит одну или несколько таких фраз.
          <mrk mtype="seg" mid="3" />Ядро <ph ctype="" id="3">&lt;MadCap:variable name="zoom_userdocs_variables.var_product_name" xmlns:MadCap="http://www.madcapsoftware.com/Schemas/MadCap.xsd" /&gt;</ph> индексирует медиафайлы и помечает места вхождения фразы (добавляет к ним метки).
          <mrk mtype="seg" mid="4" />Затем нужные медиафайлы можно искать по связанным с ними меткам.
        </target>
    </trans-unit>
    <trans-unit id="4" phase-name="pretrans" restype="x-p">
        <source>To add, delete, or modify text in the description field, click inside the description field.</source>
        <seg-source>To add, delete, or modify text in the description field, click inside the description field.</seg-source>
        <target state="final">Чтобы добавить, удалить или изменить текст в поле описания, щелкните это поле.</target>
    </trans-unit>
</body>

Обратите внимание на тег target в третьем узле trans-unit. Теги mrk должны содержать текстовые узлы, которые теперь стали одноуровневыми (по сравнению с более ранним тегом seg-source, который все еще верен), что портит структуру.

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

Вот желаемый результат:

<body>
    <trans-unit id="1" phase-name="pretrans" restype="x-h3">
        <source>Adding, Deleting or Modifying Notes in the Call Description</source>
        <seg-source>Adding, Deleting or Modifying Notes in the Call Description</seg-source>
        <target state="final">Добавление, удаление и изменение примечаний в описании звонка</target>
    </trans-unit>
    <trans-unit id="2" phase-name="pretrans" restype="x-p">
        <source>Description of Fields on RHS</source>
        <seg-source>Description of Fields on RHS</seg-source>
        <target state="final">Поле описания в правой части</target>
    </trans-unit>
    <trans-unit id="3" phase-name="pretrans" restype="x-p">
        <source>You can add descriptive text notes to a call recording, if you have the appropriate privileges to do so. These notes are visible to all users who have access to the call recording. It is recommended that each user add their initials to the notes to avoid potential confusion.</source>
        <seg-source>
            <mrk mtype="seg" mid="1">You can add descriptive text notes to a call recording, if you have the appropriate privileges to do so.</mrk>
            <mrk mtype="seg" mid="2">These notes are visible to all users who have access to the call recording.</mrk>
            <mrk mtype="seg" mid="3">It is recommended that each user add their initials to the notes to avoid potential confusion.</mrk>
        </seg-source>
        <target state="final">
            <mrk mtype="seg" mid="1"><ph ctype="" id="1">&lt;MadCap:variable name="zoom_userdocs_variables.var_product_name" xmlns:MadCap="http://www.madcapsoftware.com/Schemas/MadCap.xsd" /&gt;</ph> позволяет находить телефонные взаимодействия, содержащие или не содержащие определенные фразы.</mrk>
            <mrk mtype="seg" mid="2">Каждая речевая метка содержит одну или несколько таких фраз.</mrk>
            <mrk mtype="seg" mid="3">Ядро <ph ctype="" id="3">&lt;MadCap:variable name="zoom_userdocs_variables.var_product_name" xmlns:MadCap="http://www.madcapsoftware.com/Schemas/MadCap.xsd" /&gt;</ph> индексирует медиафайлы и помечает места вхождения фразы (добавляет к ним метки).</mrk>
            <mrk mtype="seg" mid="4">Затем нужные медиафайлы можно искать по связанным с ними меткам.</mrk>
        </target>
    </trans-unit>
    <trans-unit id="4" phase-name="pretrans" restype="x-p">
        <source>To add, delete, or modify text in the description field, click inside the description field.</source>
        <seg-source>To add, delete, or modify text in the description field, click inside the description field.</seg-source>
        <target state="final">Чтобы добавить, удалить или изменить текст в поле описания, щелкните это поле.</target>
    </trans-unit>
</body>

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

Еще один момент, на который следует обратить внимание: несмотря на то, что здесь «красиво напечатано», окончательное определение узла body находится в одной строке.

Спасибо! Я с нетерпением жду возможности узнать что-то новое!

РЕДАКТИРОВАТЬ: Обновлен исходный код выше, чтобы показать дополнительные дочерние теги в элементах <target>, которые необходимо сохранить. РЕДАКТИРОВАТЬ 2: Добавлен желаемый результат.


person Alan Forsyth    schedule 09.01.2013    source источник


Ответы (1)


Попробуйте этот XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

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

  <xsl:template match="trans-unit/target/mrk[following-sibling::text()]">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
      <xsl:value-of select="following-sibling::text()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="trans-unit/target/text()"/>

</xsl:stylesheet>

Вероятно, это дает желаемый результат:

<body>
    <trans-unit id="1" phase-name="pretrans" restype="x-h3">
        <source>Adding, Deleting or Modifying Notes in the Call Description</source>
        <seg-source>Adding, Deleting or Modifying Notes in the Call Description</seg-source>
        <target state="final" />
    </trans-unit>
    <trans-unit id="2" phase-name="pretrans" restype="x-p">
        <source>Description of Fields on RHS</source>
        <seg-source>Description of Fields on RHS</seg-source>
        <target state="final" />
    </trans-unit>
    <trans-unit id="3" phase-name="pretrans" restype="x-p">
        <source>You can add descriptive text notes to a call recording, if you have the appropriate privileges to do so. These notes are visible to all users who have access to the call recording. It is recommended that each user add their initials to the notes to avoid potential confusion.</source>
        <seg-source>
            <mrk mtype="seg" mid="1">You can add descriptive text notes to a call recording, if you have the appropriate privileges to do so.</mrk>
            <mrk mtype="seg" mid="2">These notes are visible to all users who have access to the call recording.</mrk>
            <mrk mtype="seg" mid="3">It is recommended that each user add their initials to the notes to avoid potential confusion.</mrk>
        </seg-source>
        <target state="final"><mrk mtype="seg" mid="1">При наличии соответствующих прав можно добавить описательные текстовые примечания к записи звонка.
            </mrk><mrk mtype="seg" mid="2">Эти примечания видны для всех пользователей, которые имеют доступ к записи звонка.
            </mrk><mrk mtype="seg" mid="3">Во избежание возможной путаницы каждому пользователю рекомендуется к примечаниям добавлять свои инициалы.
        </mrk></target>
    </trans-unit>
    <trans-unit id="4" phase-name="pretrans" restype="x-p">
        <source>To add, delete, or modify text in the description field, click inside the description field.</source>
        <seg-source>To add, delete, or modify text in the description field, click inside the description field.</seg-source>
        <target state="final" />
    </trans-unit>
</body>
person Kirill Polishchuk    schedule 09.01.2013
comment
Вы проверяли это? Это будет работать, за исключением того, что вывод будет содержать дополнительные пробелы, включая новую строку, после текста, что может быть неприемлемо. Кроме того, любые правильно структурированные теги target/mrk также будут изменены путем перемещения пробела между mrk в текстовый узел. Разумное использование normalize-space должно решить проблему. - person Jim Garrison; 09.01.2013
comment
@JimGarrison, я предоставил точный результат. В любом случае, OP может использовать функцию normalize-space. - person Kirill Polishchuk; 09.01.2013
comment
@JimGarrison, это не изменит правильный target/mrk. Только те, которые содержат текстовый узел следующего брата. - person Kirill Polishchuk; 09.01.2013
comment
Согласно моему тесту в OxygenXML, он изменяет как правильные, так и неправильные target/mrk (в предоставленном вводе не было неправильных примеров) и включает конечный символ новой строки и пробел отступа из следующей строки (часть того же текстового узла). У вас есть хорошо структурированное решение, его просто нужно немного подправить, чтобы оно было на 100% правильным. +1 - person Jim Garrison; 09.01.2013
comment
Я бы предложил изменить это: following-sibling::text() на это: following-sibling::node()[1]/self::text(). Таким образом гарантируется захват только текста, следующего сразу после каждого <mrk>. - person JLRishe; 09.01.2013
comment
Я заметил следующие проблемы: [1] У тегов <target>, у которых нет дочерних тегов ‹mrk›, удалены все дочерние элементы. Я исправил это, изменив третье соответствие шаблона на: match="trans-unit/target/text()[preceding-sibling::mrk] [2] Наш переводчик заметил последнюю проблему, по которой мне нужна помощь. Все теги, отличные от mrk, которые являются дочерними по отношению к <target>, удаляются. Я обновил пример кода в вопросе, чтобы включить это. Может ли кто-нибудь помочь обеспечить сохранение содержимого тега, отличного от mrk? Спасибо! - person Alan Forsyth; 15.01.2013
comment
Кстати Кирилл - спасибо за ваше предложение. Это обеспечено хорошее начало - просто нужно исправить проблему, описанную выше. - person Alan Forsyth; 16.01.2013
comment
@AlanForsyth, спасибо. Пожалуйста, предоставьте желаемый результат. - person Kirill Polishchuk; 16.01.2013
comment
Кирилл - Желаемый вывод обновлен - у вас есть возможность обновить XSLT? Опять же, это немного не в моих силах прямо сейчас - как только я получу идею, я могу изменить ее по мере необходимости. Спасибо! - person Alan Forsyth; 17.01.2013