xslt работает с ключами и переменными

Привет, весь этот вопрос связан с этим: xsl получает значения элементов из другого дерева узлов, но на этот раз у меня есть работающий xslt.

В настоящее время я работаю над следующим XML:

 <record>
  <leader>01877nz  a2200433o  4500</leader>
  <controlfield tag="001">1</controlfield>
        ... (more controlfields tag 002 to 010)
  <datafield tag="013" ind1=" " ind2=" ">
   <subfield code="a">formerge</subfield>
  </datafield>
          ... (more datafield tags, datafield tags are from 011 to 999)
  <datafield tag="150" ind1=" " ind2=" ">
   <subfield code="a">Borneo</subfield>
  </datafield>
          ... (more datafield tags, datafield tags are from 011 to 999)
  <datafield tag="550" ind1=" " ind2=" ">
   <subfield code="w">g</subfield>
   <subfield code="a">South East Asia</subfield>
   <subfield code="c">c_7260</subfield>
  </datafield>
       ... (more datafield tags, datafield tags are from 011 to 999)
  </record>

       ... (more records)

  <record>
       ... (more records fields)
       ... (more records fields)
  </record>

  <record>
   <leader>02462nz  a2200553o  4500</leader>
   <controlfield tag="001">2</controlfield>
         ... (more controlfields tag 002 to 010)
   <datafield tag="013" ind1=" " ind2=" ">
    <subfield code="a">formerge</subfield>
   </datafield>
   <datafield tag="035" ind1=" " ind2=" ">
    <subfield code="a">c_7260</subfield>
   </datafield>
       ... (more datafield tags, datafield tags are from 011 to 999)
   <datafield tag="151" ind1=" " ind2=" ">
    <subfield code="a">South East Asia</subfield>
   </datafield>
       ... (more datafield tags, datafield tags are from 011 to 999)
  </record>

У меня есть следующий xslt:

<?xml version="1.0" encoding="UTF-8"?>
 <xsl:stylesheet version="1.0" xmlns:marc="http://www.loc.gov/MARC21/slim"    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"    xmlns:dc="http://purl.org/dc/elements/1.1/"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="marc">
 <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
 <xsl:key name="term" match="//datafield[@tag='151'][subfield[@code='a']]" use="." />

 <xsl:template match="//datafield[@tag='151'][subfield[@code='a']]">
  <xsl:variable name="t550a" select="//datafield[@tag='550'][subfield[@code='a']]" />
  <xsl:for-each select="key('term','$550a')">
   <xsl:value-of select="//controlfield[@tag='001']" />
  </xsl:for-each>
 </xsl:template>

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

</xsl:stylesheet>

С этим я создал индекс всех 151 через ключи (термин). Я также создал переменную 't550a'. С помощью функции ключей я сопоставляю теги 550a (тег поля данных ="550" код подполя ="a") с термином ключ. А затем получите значение тега контрольного поля 001 этого ключа. Я также хотел получить все узлы моего xml, таким образом, "xsl:copy". С xslt, который у меня есть, кажется, что тег 151 поля данных удаляется.

Я хотел получить в 550 поле следующее:

        ... (other fields omitted)
<datafield tag="550" ind1=" " ind2=" ">
 <subfield code="w">g</subfield>
 <subfield code="a">South East Asia</subfield>
 <subfield code="c">c_7260</subfield>
 <subfield code="0">2</subfield>
</datafield>
          ... (other fields omitted)

<datafield tag="550" ind1=" " ind2=" ">
 <subfield code="w">h</subfield>
 <subfield code="a">Borneo</subfield>
 <subfield code="c">c_1017</subfield>
 <subfield code="0">1</subfield>
</datafield>

Таким образом, подполе 550 в Юго-Восточной Азии будет иметь дополнительное подполе 0 со значением 2, которое основано на контрольном поле 001 подполя 151 в Юго-Восточной Азии. А также подполе 550 Борнео будет иметь дополнительное подполе 0 со значением 1, которое основано на контрольном поле 001 подполя 151 Борнео.

Может ли кто-нибудь заставить меня сделать это правильно. Спасибо!

2 ответа

Решение

Я думаю, что ваш шаблон соответствует неправильному элементу. Если вы хотите добавить дочерний узел в поле "550", у вас должен быть шаблон, соответствующий

<xsl:template match="datafield[@tag='550'][subfield[@code='a']]">

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

 <xsl:key name="term" match="datafield[@tag='151']" use="subfield[@code='a']" />

Следующая проблема у вас с вашим определением tt50a переменная. Вы действительно хотите использовать относительное выражение здесь, потому что в данный момент он выберет первый соответствующий элемент в любом месте документа. Вы должны сделать это вместо этого (что работает, потому что вы теперь расположены на 550 узел)

<xsl:variable name="t550a" select="subfield[@code='a']" />

Однако, похоже, что вы на самом деле не используете эту переменную. Вы в настоящее время используете ключ, key('term','$550a'), использует строковый литерал, а не переменную. Вы, вероятно, хотите сделать это:

<xsl:for-each select="key('term',$t550a)">

И, наконец, в рамках xsl:for-each где вы делаете //controlfield[@tag='001'] затем выбирается первый controlfield в документе. Я думаю, что вы хотите выбрать только один в текущем record, Как record является родителем текущего datafield, вы можете просто сделать это:

<xsl:value-of select="../controlfield[@tag='001']" />

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

<xsl:stylesheet version="1.0" xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"  xmlns:dc="http://purl.org/dc/elements/1.1/"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="rdf dc marc">
 <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
 <xsl:key name="term" match="datafield[@tag='151']" use="subfield[@code='a']" />

 <xsl:template match="datafield[@tag='550'][subfield[@code='a']]">
   <xsl:variable name="t550a" select="subfield[@code='a']" />
   <xsl:copy>
     <xsl:apply-templates select="@*|node()"/>
     <xsl:for-each select="key('term',$t550a)">
       <subfield code="0">
         <xsl:value-of select="../controlfield[@tag='001']" />
       </subfield>
      </xsl:for-each>
    </xsl:copy>
 </xsl:template>

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

Это не даст результат, который вы показываете в своем вопросе точно, потому что ваш входной XML имеет только один 550 узел.

С xslt, который у меня есть, кажется, что тег 151 поля данных удаляется.

Да, это правильно, потому что это то, что вы дали ему указание:

 <xsl:template match="//datafield[@tag='151'][subfield[@code='a']]">
  <xsl:variable name="t550a" select="//datafield[@tag='550'][subfield[@code='a']]" />
  <xsl:for-each select="key('term','$550a')">
   <xsl:value-of select="//controlfield[@tag='001']" />
  </xsl:for-each>
 </xsl:template>

Это означает, что: когда datafield совпадает, обойти все условия со значением $550a и выберите (из корня!) на каждой итерации все значения контрольного поля. Я предполагаю, что вы предпочли бы иметь контрольные поля из текущего узла, как .//controlfield....?

Но вы не создаете здесь никакого элемента. Если вы хотите этого, вы, вероятно, должны добавить это. То есть:

 <xsl:template match="//datafield[@tag='151'][subfield[@code='a']]">
  <xsl:variable name="t550a" select="//datafield[@tag='550'][subfield[@code='a']]" />
  <xsl:copy>
    <xsl:for-each select="key('term','$550a')">
      <xsl:value-of select="//controlfield[@tag='001']" />
    </xsl:for-each>
   </xsl:copy>
 </xsl:template>

который будет копировать datafield,

Другие вопросы по тегам