3 Stimmen

Vergleich von 2 Knotensets anhand der Attributreihenfolge

Ich versuche, eine Art XML-Bibliothek aufzubauen, in der ich verschiedene Knoten vergleiche und sie für eine spätere Wiederverwendung kombiniere. Die Logik sollte recht einfach sein: Wenn die tag_XX-Attributwertfolge einer bestimmten Sprache gleich der tag_YY-Attributwertfolge einer anderen Sprache ist, können die Knoten kombiniert werden. Siehe folgendes XML-Beispiel

<Book>
<Section>
    <GB>
        <Para tag_GB="L1">
            <Content_GB>string_1</Content_GB>
        </Para>
        <Para tag_GB="Illanc">
            <Content_GB>string_2</Content_GB>
        </Para>
        <Para tag_GB="|PLB">
            <Content_GB>string_3</Content_GB>
        </Para>
        <Para tag_GB="L1">
            <Content_GB>string_4</Content_GB>
        </Para>
        <Para tag_GB="Sub">
            <Content_GB>string_5</Content_GB>
        </Para>
        <Para tag_GB="L3">
            <Content_GB>string_6</Content_GB>
        </Para>
        <Para tag_GB="Subbull">
            <Content_GB>string_7</Content_GB>
        </Para>
    </GB>
    <!-- German translations - OK because same attribute sequence -->
    <DE>
        <Para tag_DE="L1">
            <Content_DE>German_translation of_string_1</Content_DE>
        </Para>
        <Para tag_DE="Illanc">
            <Content_DE>German_translation of_string_2</Content_DE>
        </Para>
        <Para tag_DE="|PLB">
            <Content_DE>German_translation of_string_3</Content_DE>
        </Para>
        <Para tag_DE="L1">
            <Content_DE>German_translation of_string_4</Content_DE>
        </Para>
        <Para tag_DE="Sub">
            <Content_DE>German_translation of_string_5</Content_DE>
        </Para>
        <Para tag_DE="L3">
            <Content_DE>German_translation of_string_6</Content_DE>
        </Para>
        <Para tag_DE="Subbull">
            <Content_DE>German_translation of_string_7</Content_DE>
        </Para>
    </DE>
    <!-- Danish translations - NG because not same attribute sequence -->
    <DK>
        <Para tag_DK="L1">
            <Content_DK>Partial_Danish_translation_of_string_1</Content_DK>
        </Para>
        <Para tag_DK="L1_sub">
            <Content_DK>Partial_Danish_translation_of_string_1</Content_DK>
        </Para>
        <Para tag_DK="Illanc">
            <Content_DK>Danish_translation_of_string_2</Content_DK>
        </Para>
        <Para tag_DK="L1">
            <Content_DK>Danish_translation_of_string_4</Content_DK>
        </Para>
        <Para tag_DK="|PLB">
            <Content_DK>Danish_translation_of_string_3</Content_DK>
        </Para>
        <Para tag_DK="L3">
            <Content_DK>Danish_translation_of_string_6</Content_DK>
        </Para>
        <Para tag_DK="Sub">
            <Content_DK>Danish_translation_of_string_5</Content_DK>
        </Para>
        <Para tag_DK="Subbull">
            <Content_DK>Danish_translation_of_string_7</Content_DK>
        </Para>
    </DK>
</Section>
</Book>

Also

GB tag_GB Wertefolge = L1 -> Illanc -> ... -> SubBul

DE tag_DE Wertefolge = L1 -> Illanc -> ... -> SubBul (wie GB, also ok)

DK tag_DK value sequence = L1 -> L1.sub -> Oops, erwartet Illanc, was bedeutet, dass diese Sequenz nicht mit GB übereinstimmt und das Gebietsschema ignoriert werden kann

Da deutsche und englische Knotensätze die gleiche Attributfolge haben, möchte ich sie wie folgt kombinieren:

<Book>
<Dictionary>
    <Para tag="L1">
        <Content_GB>string_1</Content_GB>
        <Content_DE>German_translation of_string_1</Content_DE>
    </Para>
    <Para tag="Illanc">
        <Content_GB>string_2</Content_GB>
        <Content_DE>German_translation of_string_2</Content_DE>
    </Para>
    <Para tag="|PLB">
        <Content_GB>string_3</Content_GB>
        <Content_DE>German_translation of_string_3</Content_DE>
    </Para>
    <Para tag="L1">
        <Content_GB>string_4</Content_GB>
        <Content_DE>German_translation of_string_4</Content_DE>
    </Para>
    <Para tag="Sub">
        <Content_GB>string_5</Content_GB>
        <Content_DE>German_translation of_string_5</Content_DE>
    </Para>
    <Para tag="L3">
        <Content_GB>string_6</Content_GB>
        <Content_DE>German_translation of_string_6</Content_DE>
    </Para>
    <Para tag="Subbull">
        <Content_GB>string_7</Content_GB>
        <Content_DE>German_translation of_string_7</Content_DE>
    </Para>
</Dictionary>
</Book>

Das Stylesheet, das ich verwende, ist das folgende :

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" xmlns="http://www.w3.org/1999/xhtml" encoding="UTF-8" indent="yes"/>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="text()">
    <xsl:value-of select="normalize-space(.)"/>
</xsl:template>
<xsl:template match="Section">
    <!-- store reference tag list -->
    <xsl:variable name="Ref_tagList" select="GB/Para/attribute()[1]"/>
    <Dictionary>
        <xsl:for-each select="GB/Para">
            <xsl:variable name="pos" select="position()"/>
            <Para tag="{@tag_GB}">
                <!-- Copy English Master -->
                <xsl:apply-templates select="element()[1]"/>
                <xsl:for-each select="//Book/Section/element()[not(self::GB)]">
                    <!-- store current locale tag list -->
                    <xsl:variable name="Curr_tagList" select="Para/attribute()[1]"/>
                    <xsl:if test="$Ref_tagList = $Curr_tagList">
                        <!-- Copy current locale is current tag list equals reference tag list -->
                        <xsl:apply-templates select="Para[position()=$pos]/element()[1]"/>
                    </xsl:if>
                </xsl:for-each>
            </Para>
        </xsl:for-each>
    </Dictionary>
</xsl:template>
</xsl:stylesheet>

Abgesehen von wahrscheinlich nicht der effizienteste Weg, dies zu tun (ich bin ziemlich neu in der xslt Spiel...) es funktioniert auch nicht. Die Logik, die ich im Sinn hatte, ist die Attributmenge des englischen Masters zu nehmen, und wenn die Attributmenge eines anderen Gebietsschemas gleich ist, kopiere ich, wenn nicht ignoriere ich. Aber aus irgendeinem Grund werden auch Nodesets, die eine andere Attributsequenz haben, fröhlich kopiert (wie unten zu sehen). Kann mir jemand sagen, wo meine Logik mit der Realität kollidiert? Vielen Dank im Voraus!

Aktuelle Ausgabe Einschließlich Dänisch, das ignoriert werden sollte ...

<Book>
<Dictionary>
    <Para tag="L1">
        <Content_GB>string_1</Content_GB>
        <Content_DE>German_translation of_string_1</Content_DE>
        <Content_DK>Partial_Danish_translation_of_string_1</Content_DK>
    </Para>
    <Para tag="Illanc">
        <Content_GB>string_2</Content_GB>
        <Content_DE>German_translation of_string_2</Content_DE>
        <Content_DK>Partial_Danish_translation_of_string_1</Content_DK>
    </Para>
    <Para tag="|PLB">
        <Content_GB>string_3</Content_GB>
        <Content_DE>German_translation of_string_3</Content_DE>
        <Content_DK>Danish_translation_of_string_2</Content_DK>
    </Para>
    <Para tag="L1">
        <Content_GB>string_4</Content_GB>
        <Content_DE>German_translation of_string_4</Content_DE>
        <Content_DK>Danish_translation_of_string_4</Content_DK>
    </Para>
    <Para tag="Sub">
        <Content_GB>string_5</Content_GB>
        <Content_DE>German_translation of_string_5</Content_DE>
        <Content_DK>Danish_translation_of_string_3</Content_DK>
    </Para>
    <Para tag="L3">
        <Content_GB>string_6</Content_GB>
        <Content_DE>German_translation of_string_6</Content_DE>
        <Content_DK>Danish_translation_of_string_6</Content_DK>
    </Para>
    <Para tag="Subbull">
        <Content_GB>string_7</Content_GB>
        <Content_DE>German_translation of_string_7</Content_DE>
        <Content_DK>Danish_translation_of_string_5</Content_DK>
    </Para>
</Dictionary>
</Book>

1voto

Emiliano Poggi Punkte 23692

Dies ist vielleicht nicht die beste Lösung. Ich habe die folgenden XSLT 2.0-Funktionen verwendet:

  • Ich habe die Reihenfolge der Attribute mit string-join() .
  • Ich habe die Möglichkeit der Verwendung von RTF-Variablen genutzt

Es gibt wahrscheinlich mehr XSLT 2.0-Funktionen, die Ihr Problem lösen können. aber ich denke, das GROSSE Problem hier ist Ihr Input-Dokument.

Es tut mir leid, dass ich keinen Blick auf Ihre aktuelle Transformation geworfen habe. Habe gerade eine von Grund auf neu implementiert. Hoffe es hilft:

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

    <xsl:template match="GB">
        <Book>
            <Dictionary>

                <xsl:variable name="matches">
                    <xsl:for-each select="following-sibling::*
                        [string-join(Para/@*,'-')
                        = string-join(current()/Para/@*,'-')]">
                        <match><xsl:copy-of select="Para/*"/></match>
                    </xsl:for-each>
                </xsl:variable>

                <xsl:apply-templates select="Para">
                    <xsl:with-param name="matches" select="$matches"/>
                </xsl:apply-templates>

            </Dictionary>
        </Book>
    </xsl:template>

    <xsl:template match="Para[parent::GB]">
        <xsl:param name="matches"/>
        <xsl:variable name="pos" select="position()"/>
        <Para tag="{@tag_GB}">
            <xsl:copy-of select="Content_GB"/>
            <xsl:copy-of select="$matches/match/*[position()=$pos]"/>
        </Para>
    </xsl:template>

    <xsl:template match="text()"/>

</xsl:stylesheet> 

Bei Anwendung auf das in der Frage angegebene Eingabedokument ergibt sich die folgende Ausgabe:

<Book>
   <Dictionary>
      <Para tag="L1">
         <Content_GB>string_1</Content_GB>
         <Content_DE>German_translation of_string_1</Content_DE>
      </Para>
      <Para tag="Illanc">
         <Content_GB>string_2</Content_GB>
         <Content_DE>German_translation of_string_2</Content_DE>
      </Para>
      <Para tag="|PLB">
         <Content_GB>string_3</Content_GB>
         <Content_DE>German_translation of_string_3</Content_DE>
      </Para>
      <Para tag="L1">
         <Content_GB>string_4</Content_GB>
         <Content_DE>German_translation of_string_4</Content_DE>
      </Para>
      <Para tag="Sub">
         <Content_GB>string_5</Content_GB>
         <Content_DE>German_translation of_string_5</Content_DE>
      </Para>
      <Para tag="L3">
         <Content_GB>string_6</Content_GB>
         <Content_DE>German_translation of_string_6</Content_DE>
      </Para>
      <Para tag="Subbull">
         <Content_GB>string_7</Content_GB>
         <Content_DE>German_translation of_string_7</Content_DE>
      </Para>
   </Dictionary>
</Book>

1voto

Mads Hansen Punkte 58777

Dieses Stylesheet verwendet die <xsl:for-each-group>

  1. Erstens: Gruppiert die Elemente nach ihrer Reihenfolge der Para/@* Werte
  2. Dann gruppieren Sie für jede dieser Sequenzen die Para anhand der Anzahl der following sibling Elemente, die Attribute haben, die mit "tag" beginnen.

Ich habe Prädikatsfilter auf die Treffer für @* um sicherzustellen, dass nur die mit "tag_" beginnenden Einträge verglichen werden. Das ist vielleicht nicht notwendig, würde aber dazu beitragen, dass es auch dann noch funktioniert, wenn der Instanz-XML weitere Attribute hinzugefügt werden.

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" xmlns="http://www.w3.org/1999/xhtml" encoding="UTF-8"
        indent="yes"/>
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

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

    <xsl:template match="text()" priority="1">
        <xsl:value-of select="normalize-space(.)"/>
    </xsl:template>

    <xsl:template match="Section">
        <xsl:for-each-group select="*"
            group-adjacent="string-join(
            Para/@*[starts-with(local-name(),'tag_')],'|')">
            <Dictionary>
                <xsl:for-each-group select="current-group()/Para"
                    group-by="count(
                    following-sibling::*[@*[starts-with(local-name(),'tag_')]])">
                    <Para tag="{(current-group()/@*[starts-with(local-name(),'tag_')])[1]}">
                        <xsl:copy-of select="current-group()/*"/>
                    </Para>
                </xsl:for-each-group>
            </Dictionary>
        </xsl:for-each-group>
    </xsl:template>

</xsl:stylesheet>

Bei Anwendung auf die XML-Beispieleingabe ergibt sich folgende Ausgabe:

<Book>
   <Dictionary>
      <Para tag="L1">
         <Content_GB>string_1</Content_GB>
         <Content_DE>German_translation of_string_1</Content_DE>
      </Para>
      <Para tag="Illanc">
         <Content_GB>string_2</Content_GB>
         <Content_DE>German_translation of_string_2</Content_DE>
      </Para>
      <Para tag="|PLB">
         <Content_GB>string_3</Content_GB>
         <Content_DE>German_translation of_string_3</Content_DE>
      </Para>
      <Para tag="L1">
         <Content_GB>string_4</Content_GB>
         <Content_DE>German_translation of_string_4</Content_DE>
      </Para>
      <Para tag="Sub">
         <Content_GB>string_5</Content_GB>
         <Content_DE>German_translation of_string_5</Content_DE>
      </Para>
      <Para tag="L3">
         <Content_GB>string_6</Content_GB>
         <Content_DE>German_translation of_string_6</Content_DE>
      </Para>
      <Para tag="Subbull">
         <Content_GB>string_7</Content_GB>
         <Content_DE>German_translation of_string_7</Content_DE>
      </Para>
   </Dictionary>
   <Dictionary>
      <Para tag="L1">
         <Content_DK>Partial_Danish_translation_of_string_1</Content_DK>
      </Para>
      <Para tag="L1_sub">
         <Content_DK>Partial_Danish_translation_of_string_1</Content_DK>
      </Para>
      <Para tag="Illanc">
         <Content_DK>Danish_translation_of_string_2</Content_DK>
      </Para>
      <Para tag="L1">
         <Content_DK>Danish_translation_of_string_4</Content_DK>
      </Para>
      <Para tag="|PLB">
         <Content_DK>Danish_translation_of_string_3</Content_DK>
      </Para>
      <Para tag="L3">
         <Content_DK>Danish_translation_of_string_6</Content_DK>
      </Para>
      <Para tag="Sub">
         <Content_DK>Danish_translation_of_string_5</Content_DK>
      </Para>
      <Para tag="Subbull">
         <Content_DK>Danish_translation_of_string_7</Content_DK>
      </Para>
   </Dictionary>
</Book>

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X