2012-10-01 10 views
7

Mój model danych jest następujący:uzyskać najbardziej aktualne w dokumentacji xml

<Club> 
<Captain> 
<Name></Name> 
<DateOfBirth>15-01-1985</DateOfBirth> 
</Captain> 
<PlayingStaff> 
<Player> 
<DateOfBirth>14-01-1993</DateOfBirth> 
</Player> 
<Player> 
<DateOfBirth>07-12-1975</DateOfBirth> 
</Player> 
<Player> 
<DateOfBirth>11-11-1991</DateOfBirth> 
</Player> 
</PlayingStaff> 
</Club> 

Próbowałem za pomocą odpowiedź udzieloną tutaj: XSLT: Getting the latest date ale isnt daje mi żadnej wartości.

Staram się, aby najmłodszy gracz przeszedł do funkcji zewnętrznej.

Robię to w BizTalk więc muszę trzymać się XSLT1

Moja praca do tej pory jest w następujący sposób:

<xsl:variable name="youngestPlayer"> 
      <xsl:for-each select="$ClubRoot/*[local-name()='PlayingStaff']/*[local-name()='Player']"> 
       <xsl:sort select="./*[local-name()='DateOfBirth']" order="descending"/> 
       <xsl:if test="position() = 1"> 
        <xsl:value-of select="DateOfBirth"/> 
       </xsl:if> 
      </xsl:for-each> 
     </xsl:variable> 
     <xsl:variable name="IsYoungestPlayerUnderAgeLimit" select="externalfunctionreturningboolean"> 
      <xsl:element name="blahhh"><xsl:value-of select="$IsYoungestPlayerUnderAgeLimit"/></xsl:element> 
      <xsl:element name="blahhh"><xsl:value-of select="$youngestPlayer"/></xsl:element> 

Jest to część dużej matrycy - nie mogę naprawdę zmienić, ale wartość kiłę jest "<xsl:variable name="ClubRoot" select="/*[1]"/>" aby zapewnić mogę odczytać jego węzły potomne.

zawsze jestem coraz

<blahhh>false</blahhh> 
<blahhh/> 

jako moje wartości debugowania ... więc nie podniosę wartości, której oczekuję.

Czy ktoś może wskazać miejsce, w którym popełniłem błąd?

Z powyższych danych oczekiwałbym wartości 14-01-1993 w mojej najmłodszej zmiennej Player. Ale puste.

Odpowiedz

6

Problemem jest to, że XSLT1.0 tak naprawdę nie ma pojęcia o terminach, dzięki czemu skutecznie sortowania przez DateOfBirth elementów tak, jakby były po prostu normalne struny. Jeśli można mieć pewność daty zawsze są w formacie DD-MM-YYYY można użyć manipulacji ciąg do sortowania przez rok, miesiąc i dzień

<xsl:sort select="number(substring(DateOfBirth, 7, 4))" order="descending"/> 
<xsl:sort select="number(substring(DateOfBirth, 3, 2))" order="descending"/> 
<xsl:sort select="number(substring(DateOfBirth, 1, 2))" order="descending"/> 

Więc otrzymuje następujące XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:template match="/Club"> 
     <xsl:for-each select="PlayingStaff/Player"> 
     <xsl:sort select="number(substring(DateOfBirth, 7, 4))" order="descending"/> 
     <xsl:sort select="number(substring(DateOfBirth, 3, 2))" order="descending"/> 
     <xsl:sort select="number(substring(DateOfBirth, 1, 2))" order="descending"/> 

     <xsl:if test="position() = 1"> 
      <xsl:value-of select="DateOfBirth"/> 
     </xsl:if> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

Gdy stosowana do XML, co następuje wyjście

14-01-1993 
+2

przy użyciu funkcji translate(), można zmniejszyć liczbę xsl: sort instrukcje od 3 do 1 i uprość wyrażenie "xsl: sort/@ select". –

1

powodem data sortowania połączonego odniesienia „obrobione”, ponieważ był w formacie yyyy-MM-dd, w przeciwieństwie do y nasz format dd-MM-yyyy.

Alternatywą dla propozycji Tima C/Seana jest użycie funkcji skryptu C# (ponieważ używasz BizTalk), aby przywrócić datę do sortowalnej według twojego linku - ale pamiętaj, że jest mało prawdopodobne, aby była tak wydajna jak natywna funkcje xslt. Zauważ też, że możesz potrzebować użyć msxsl:node-set dla zmiennych, aby powiedzieć analizatorowi BizTalk, że jest to fragment.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:userCSharp="http://schemas.microsoft.com/BizTalk/2003/userCSharp" 
       xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
       exclude-result-prefixes="userCSharp msxsl" 
       > 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="/"> 
     <xsl:variable name="ClubRoot" select="/*[1]"/> 
     <xsl:variable name="orderedPlayers"> 
      <xsl:for-each select="msxsl:node-set($ClubRoot)/*[local-name()='PlayingStaff']/*[local-name()='Player']"> 
       <xsl:sort select="userCSharp:makeSortableDate(string(*[local-name()='DateOfBirth']), 'dd-MM-yyyy')" order="descending"/> 
       <xsl:copy-of select="node() | @*"/> 
      </xsl:for-each> 
     </xsl:variable> 

     <xsl:variable name="youngestPlayerDOB"> 
      <xsl:value-of select="msxsl:node-set($orderedPlayers)[1]/DateOfBirth/text()" /> 
     </xsl:variable> 

     <xsl:element name="blahhh"> 
      <xsl:variable name="IsYoungestPlayerUnderAgeLimit" select="userCSharp:externalfunctionreturningboolean($youngestPlayerDOB)" /> 
      <xsl:value-of select="$IsYoungestPlayerUnderAgeLimit"/> 
     </xsl:element> 
     <xsl:element name="blahhh"> 
      <xsl:value-of select="$youngestPlayerDOB"/> 
     </xsl:element> 
    </xsl:template> 

    <msxsl:script language="C#" implements-prefix="userCSharp"> 
     <![CDATA[ 
     public System.String makeSortableDate(System.String yourDate, string format) 
     { 
      return (System.DateTime.ParseExact(yourDate, format, System.Globalization.CultureInfo.InvariantCulture).ToString("yyyy-MM-dd")); 
     } 

     public bool externalfunctionreturningboolean(System.String dobString) 
     { 
      System.DateTime someDate; 
      if (System.DateTime.TryParse(dobString, out someDate)) 
      { 
       // NB : Doesn't work out leap years correctly! 
       if ((System.DateTime.Now - someDate).Days < 21 * 365.25) 
       { 
        return true; 
       } 
      } 
      return false; 
     } 
    ]]> 
    </msxsl:script> 

</xsl:stylesheet> 

Wziąłem hack w funkcji i domyślił się, że nieletni limit wynosi 21. Powyższe powraca

<blahhh>true</blahhh> 
<blahhh>14-01-1993</blahhh> 
Powiązane problemy