xslt найти и вставить и / или заменить на инкрементный номер - PullRequest
0 голосов
/ 20 ноября 2010

У меня есть список терминов в XML. Термины могут иметь термин type или pt. Если термин является термином типа nd, он не имеет идентификатора, но вместо этого ссылается на PT типа термина, который имеет идентификатор. Мне нужно сделать две вещи.

  1. замените XXX для значения termId инкрементным числом для termtype nd, чтобы все термины имели идентификатор.

  2. , где termType ND ссылается на PT termType, мне нужно как-то найти его идентификатор и вставить его:


<Zthes>
<term>
<termName>Term 1</termName>
<termId>insert new term id N+1 </termId>
<termType>Nd</termType>

 <relation>
 <relationType>USE</relationType>
 <termId>insert ID of term 2 <termID>
<termName>Term2</termName>
 </relation>
</term>

<term>
<termName>Term 2</termName>
<termId>587889</termId>
<termType>pt</termType>
 </term>

</zthes>

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

ТАКЖЕ, это не должно быть xslt. Я работаю с разработчиком, который сказал, что это лучший способ сделать это, но что ответ был слишком тривиальным для него, чтобы беспокоиться. Хотя это слишком сложно для меня!

Ответы [ 2 ]

0 голосов
/ 20 ноября 2010

Это одиночное преобразование :

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

 <xsl:key name="ktermPtIdByName"
      match="term[termType='pt']/termId"
      use="../termName"/>

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

 <xsl:template match="term[termType='Nd']/termId">
  <termId>
    <xsl:number level="single" count="/*/term[termType='Nd']"/>
  </termId>
 </xsl:template>

 <xsl:template match="relation/termId">
  <termId>
    <xsl:value-of select="key('ktermPtIdByName', ../termName)"/>
  </termId>
 </xsl:template>
</xsl:stylesheet>

при применении к следующему документу XML (ваш XML-код исправлен, чтобы быть синтаксически правильно сформированным и семантически правильным, а затем увеличен в два раза, чтобы сделать более интересным):

<zthes>
    <term>
        <termName>Term 1</termName>
        <termId></termId>
        <termType>Nd</termType>
        <relation>
            <relationType>USE</relationType>
            <termId></termId>
            <termName>Term 2</termName>
        </relation>
    </term>
    <term>
        <termName>Term 2</termName>
        <termId>587889</termId>
        <termType>pt</termType>
    </term>
    <term>
        <termName>Term 3</termName>
        <termId></termId>
        <termType>Nd</termType>
        <relation>
            <relationType>USE</relationType>
            <termId></termId>
            <termName>Term 4</termName>
        </relation>
    </term>
    <term>
        <termName>Term 4</termName>
        <termId>587890</termId>
        <termType>pt</termType>
    </term>
</zthes>

дает желаемый, правильный результат :

<zthes>
   <term>
      <termName>Term 1</termName>
      <termId>1</termId>
      <termType>Nd</termType>
      <relation>
         <relationType>USE</relationType>
         <termId>587889</termId>
         <termName>Term 2</termName>
      </relation>
   </term>
   <term>
      <termName>Term 2</termName>
      <termId>587889</termId>
      <termType>pt</termType>
   </term>
   <term>
      <termName>Term 3</termName>
      <termId>2</termId>
      <termType>Nd</termType>
      <relation>
         <relationType>USE</relationType>
         <termId>587890</termId>
         <termName>Term 4</termName>
      </relation>
   </term>
   <term>
      <termName>Term 4</termName>
      <termId>587890</termId>
      <termType>pt</termType>
   </term>
</zthes>

Примечание :

  1. Правило идентификации используется для копирования каждого узла "как есть".

  2. Шаблоны переопределяют правило идентификации только для элементов, которые необходимо изменить.

  3. <xsl:number> используется для (мне лень) вычисления требуемого termId.

  4. Ключ используется для наиболее эффективного поиска termId по его TermName

0 голосов
/ 20 ноября 2010

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

Я бы предложил сделать это с двумя отдельными XSL. Конечно, можно объединить два прохода XSL в один XSL, но фактическая реализация зависит от используемой вами библиотеки XSL (здесь есть некоторые подробности, если вам интересно: http://www.oreillynet.com/xml/blog/2006/08/multistage_xslt_scripts.html)

Первый проход должен пройти через все ваши термины и присвоить номера тем, которые помечены как «Nd». Я догадываюсь:

(a) Если у них есть идентификатор, их тип должен быть изменен на «pt», и

(b) Порядок этих элементов не является конкретным.

Причина, по которой я предлагаю сделать это в качестве отдельного прохода, заключается в том, что один из ваших терминов может ссылаться на другой термин, который сам по себе является типом «Nd». Если бы это было так, то у него не было бы действительного номера для ссылки (поскольку ни один не был бы назначен)

XSL для выполнения этого шага будет выглядеть примерно так:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="term[termType = 'Nd']">
        <term>
            <xsl:copy-of select="termName"/>
            <termId><xsl:value-of select="position()"/></termId>
            <termType>pt</termType>
            <xsl:copy-of select="relation" />
        </term>
    </xsl:template>

    <xsl:template match="/">
        <zthes>
            <xsl:apply-templates select="zthes/term[termType = 'Nd']"/>
            <xsl:copy-of select="zthes/term[termType = 'pt']"/>
        </zthes>
    </xsl:template>

</xsl:stylesheet>

Вторым шагом было бы взять выходные данные этого преобразования и протолкнуть его через второе преобразование, которое будет «заполнять» идентификаторы терминов «отношение». Это довольно простое преобразование идентичности (точная, рекурсивная копия) с одним специальным правилом. Специальное правило идентифицирует termIds внутри узлов отношений и заменяет правильный termId на основе сопоставления имен. Это преобразование выглядит так:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="relation/termId">
        <termId>
            <xsl:value-of select="/zthes/term[termName=current()/../termName]/termId"/>
        </termId>
    </xsl:template>

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

</xsl:stylesheet>

Я ожидаю, что это сделает примерно то, что вы после. Это не будет работать как есть на ваших текущих входных данных, потому что ваш текущий ввод на самом деле является недопустимым XML. :) Чтобы это исправить:

  • Измените 'Zthes' на 'zthes' в открывающий тег XML чувствителен к регистру
  • Внутри первого блока 'Relations' убедитесь, что вы закрыли 'termId' узел. На данный момент вы открываете это дважды и не закрывая его.
  • Внутри 'termName' блока 'отношение' вы ссылались на 'Term2' когда ты имел в виду «срок 2». Есть разница между пробелами, которая остановит их соответствие.

Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...