XSL: заменить два родственных элемента одним

Я пытаюсь заменить этот XML:

<name type="personal" authority="local">
  <namePart>Gertrude</namePart>
  <namePart type="termsOfAddress">Aunt</namePart>
  <role>
     <roleTerm authority="marcrelator" type="text">Correspondent</roleTerm>
     <roleTerm authority="marcrelator" type="code">crp</roleTerm>
  </role>
</name>

с этим XML:

<name type="personal" authority="local">
  <namePart>Aunt Gertrude</namePart>
  <role>
     <roleTerm authority="marcrelator" type="text">Correspondent</roleTerm>
     <roleTerm authority="marcrelator" type="code">crp</roleTerm>
  </role>
</name>

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

Первый метод

<xsl:template match="* | processing-instruction() | comment()">
    <xsl:copy>
        <xsl:copy-of select="@*" copy-namespaces="no"/>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
<xsl:template match="//name/namePart[matches(., 'Gertrude')
                    and following-sibling::namePart[@type='termsOfAddress'
                        and matches(., 'Aunt')]]">
    <namePart>Aunt Gertrude</namePart>
</xsl:template>
<xsl:template match="//name/namePart[@type='termsOfAddress'
                       and matches(., 'Aunt')
                       and preceding-sibling::namePart[matches(., 'Gertrude')]]"/>

Второй метод

    <xsl:template match="* | processing-instruction() | comment()">
    <xsl:copy>
        <xsl:copy-of select="@*" copy-namespaces="no"/>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
<xsl:template match="//name[descendant::namePart[matches(., 'Gertrude')]
                         and descendant::namePart[@type='termsOfAddress' 
                         and matches(., 'Aunt')]]/namePart">
    <namePart>Aunt Gertrude</namePart>
</xsl:template>

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

<name type="personal" authority="local">
   <namePart>Aunt Gertrude</namePart>
   <namePart>Aunt Gertrude</namePart>
   <role>
      <roleTerm authority="marcrelator" type="text">Correspondent</roleTerm>
      <roleTerm authority="marcrelator" type="code">crp</roleTerm>
   </role>
</name>

Это не то, чего я хочу.

Есть ли способ выбрать оба элемента namePart и заменить их одним?


person user1655528    schedule 07.09.2012    source источник
comment
Есть много методов, однако вы не объясняете, в каком порядке (правило упорядочения) значения должны быть объединены в одну строку.   -  person Dimitre Novatchev    schedule 08.09.2012


Ответы (1)


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

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

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

    <namePart>
      <xsl:apply-templates select="namePart">
        <xsl:sort select="count(@*)"/>
      </xsl:apply-templates>
    </namePart>
    <xsl:apply-templates select="*[not(self::namePart)]"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="namePart">
   <xsl:if test="not(position()=1)"><xsl:text> </xsl:text></xsl:if>
   <xsl:value-of select="."/>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному XML-документу:

<name type="personal" authority="local">
  <namePart>Gertrude</namePart>
  <namePart type="termsOfAddress">Aunt</namePart>
  <role>
     <roleTerm authority="marcrelator" type="text">Correspondent</roleTerm>
     <roleTerm authority="marcrelator" type="code">crp</roleTerm>
  </role>
</name>

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

<name type="personal" authority="local">
   <namePart>Gertrude Aunt</namePart>
   <role>
      <roleTerm authority="marcrelator" type="text">Correspondent</roleTerm>
      <roleTerm authority="marcrelator" type="code">crp</roleTerm>
   </role>
</name>
person Dimitre Novatchev    schedule 08.09.2012
comment
Спасибо Алехандро, который предупредил меня о неправильном представлении в первой версии этого ответа. - person Dimitre Novatchev; 08.09.2012
comment
К сожалению, есть и другие элементы <namePart>, которые я ДЕЙСТВИТЕЛЬНО хочу скопировать в документ, соответствующий требованию <xsl:if test="not(position()=1)">. Документ, с которым я работаю, на самом деле немного больше, чем я привел здесь, и включает несколько деревьев //name/namePart. В этом случае мое первое решение может быть лучшим, потому что оно учитывает конкретного родственного элемента, который мне не нужен, хотя я мог бы придумать некоторый код в шаблоне * | processing-instruction() | comment() для учета <nameParts>, который мне не нужен. Спасибо! - person user1655528; 08.09.2012
comment
@user1655528 user1655528, если вы хотите получить полезный ответ на проблему, вам необходимо включить достаточно данных. Даже в этом примере вырезания не указано, в каком порядке следует объединять строки. Я настоятельно рекомендую вам подумать и задать новый вопрос, содержащий достаточный и репрезентативный XML-документ и точный желаемый результат, а также предоставить полные, недвусмысленные требования — возможно, в виде списка различных вариантов использования, чтобы люди не t должны угадывать и давать ответы, которые из-за их догадок не те, которые вы хотите. - person Dimitre Novatchev; 08.09.2012
comment
Прошу прощения, ваш ответ был на самом деле очень полезен, поскольку он помог мне лучше понять требования моей проблемы, почему первый пример работает, а второй нет, и что мне нужно учитывать при составлении XSL. Я пытался сделать свой вопрос максимально применимым, но в итоге получился двусмысленным. Действительно, из-за моего невежества я на самом деле задал вопрос, на который, как мне кажется, я уже ответил: как выбрать два узла. Мой первый пример на самом деле выбирает два узла, просто первый шаблон ТАКЖЕ выбирает узел, который мне не нужен. Еще раз спасибо и извините. - person user1655528; 08.09.2012