XSLT Gouping, для каждого и замешанный цикл. Как устранить дубликаты? - PullRequest
0 голосов
/ 28 марта 2012

Надеюсь найти помощь гуру, чтобы выяснить следующую проблему.

У меня есть два XML-файла. Первый здесь ( text.xml ):

<text>
<ref>Author1, Title1, Date1</ref>
<ref>Author75, Title75, Date2</ref>
<ref>Author2, Title2, Date2</ref>
<ref>Author3, Title3, Date3</ref>
<text>

А второй вот так ( list.xml ):

<list>
<bibl xml:id="1"><author>Author1</author><date>Date1</date></bibl>
<bibl xml:id="2"><author>Author2</author><date>Date2</date></bibl>
<bibl xml:id="3"><author>Author3</author><date>Date3</date></bibl>
</list>

Я хочу запросить text.xml и проверить list.xml , чтобы добавить @xml: id (из list.xml ) к <ref> (из text.xml ), которые содержат одного и того же автора и дату. Если нет, то просто скопируйте оригинал <ref>.

Итак, я хочу получить:

<ref xml:id="1">Author1, Title1, Date1</ref> 
<ref>Author75, Title75, Date2</ref>
<ref xml:id="2>Author2, Title2, Date2</ref>
etc.

My XSLT точно определить все соответствия:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

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

    <xsl:template match="ref">
        <xsl:variable name="ref" select="."/>
        <xsl:for-each select="document('list.xml')//bibl">
            <xsl:variable name="bibl" select="."/>
            <xsl:variable name="author" select="author"/>
            <xsl:variable name="date" select="date"/>
            <xsl:choose>
                <xsl:when test="contains($ref, $author) and contains($ref, $date)">
                    <ref>
                        <xsl:attribute name="xml:id">
                            <xsl:value-of select="$bibl/@xml:id"/>
                        </xsl:attribute>
                        <xsl:value-of select="$ref"/>
                    </ref>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="$ref"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

Но тогда нет соответствия, это не просто правильное копирование <ref>, а копирование всех <ref> количества раз, которое у меня есть <bibl> узлов во втором файле.

Итак, проблема в <xsl:otherwise><xsl:copy-of select="$ref"/></xsl:otherwise>. Любые идеи, как я могу получить только это отдельное значение мне нужно? Я знаю, что это должно быть очень просто на самом деле, и я пытаюсь использовать ключ, генерировать идентификатор, для каждой группы, различные значения, но не могу понять это.

Ответы [ 2 ]

0 голосов
/ 28 марта 2012

Проблема в том, что вы создаете элемент ref для каждой итерации цикла for-each , независимо от того, есть совпадение или нет.

В этом случае вам нужно создать элемент ref вне for-each , а затем создать только атрибут id для соответствующего элемента внутри цикла

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="ref">
      <xsl:variable name="ref" select="."/>
      <ref>
         <xsl:apply-templates select="@* "/>
         <xsl:for-each select="document('list.xml')//bibl">
            <xsl:variable name="bibl" select="."/>
            <xsl:variable name="author" select="author"/>
            <xsl:variable name="date" select="date"/>
            <xsl:choose>
               <xsl:when test="contains($ref, $author) and contains($ref, $date)">
                  <xsl:attribute name="xml:id">
                     <xsl:value-of select="$bibl/@xml:id"/>
                  </xsl:attribute>
               </xsl:when>
            </xsl:choose>
         </xsl:for-each>
         <xsl:apply-templates select="node()"/>
      </ref>
   </xsl:template>
</xsl:stylesheet>

При применении к вашему образцу XML выводится следующее:

<text>
   <ref xml:id="1">Author1, Title1, Date1</ref>
   <ref>Author75, Title75, Date2</ref>
   <ref xml:id="2">Author2, Title2, Date2</ref>
   <ref xml:id="3">Author3, Title3, Date3</ref>
</text>

Однако ваш текущий метод не очень эффективен, поскольку для каждого элемента ref вы выполняете итерацию по всем элементам bibl . Другой подход заключается в извлечении автора и даты из элементов ref , а затем непосредственно поиск элемента bibl

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="ref">
      <xsl:variable name="author" select="normalize-space(substring-before(., ','))"/>
      <xsl:variable name="date" select="normalize-space(substring-after(substring-after(., ','), ','))"/>
      <ref>
         <xsl:apply-templates select="@* "/>
         <xsl:apply-templates select="document('list.xml')//bibl[author=$author][date=$date]"/>
         <xsl:apply-templates select="node()"/>
      </ref>
   </xsl:template>

   <xsl:template match="bibl">
      <xsl:attribute name="xml:id">
         <xsl:value-of select="@xml:id"/>
      </xsl:attribute>
   </xsl:template>
</xsl:stylesheet>

Это также должно дать те же результаты.

0 голосов
/ 28 марта 2012

EDIT: хм ... слишком много внимания синтаксису XSL, я должен был видеть это раньше ... у вас есть скрытый внешний цикл над каждым ref и внутренний цикл над каждым bibl. Вы генерируете один элемент для каждого bibl для каждого ref независимо от совпадения или отсутствия совпадения. Таким образом, вместо xsl:otherwise вам нужно проверить после цикла for-each, чтобы увидеть, не было ли совпадений, и выполнить copy-of, если необходимо.

Не уверен, как сделать проверку, хотя ... возможно, используя position() и count() сгенерированных <ref> s, извините ... у вас больше нет времени думать об этом прямо сейчас.

не совсем объяснение, а обходной путь:

<xsl:otherwise>
   <ref>
      <xsl:value-of select="$ref"/>
   </ref>
</xsl:otherwise>

Я предполагаю, что проблема заключается в $ ref, который на данный момент не является выражением xpath (если я правильно помню xsl-t)

...