2012-04-05 28 views
5

Với XML sau:XSLT: Làm cách nào để xuất dữ liệu được bản địa hóa?

<?xml version="1.0" encoding="UTF-8" ?> 
<?xml-stylesheet type="text/xsl" href="form.xsl"?> 
<Document> 
    <Translations> 
    <Translation name="Resource">Invariant Resource</Translation> 
    <Translation name="Resource" lang="en">English Resource</Translation> 
    <Translation name="Resource" lang="en-CA">Canadian English Resource</Translation> 
    <Translation name="Resource" lang="en-GB">British English Resource</Translation> 
    <Translation name="Message">Invariant Message</Translation> 
    <Translation name="Message" lang="en">English Message</Translation> 
    <Translation name="Message" lang="en-CA">Canadian English Message</Translation> 
    <Translation name="Message" lang="en-AU">Australian English Message</Translation> 
    </Translations> 
</Document> 

tôi cần phải chọn một tập hợp các yếu tố dịch như vậy mà bộ chứa giá trị duy nhất cho "tên" thuộc tính, và "phù hợp nhất" cho một miền địa phương nhất định ('en -US ',' es-MX ',' fr ', v.v.). Khi tôi nói phù hợp nhất, tôi muốn tìm kiếm một phần tử với miền địa phương phù hợp, sau đó tìm kiếm một kết quả dựa trên hai ký tự đầu tiên, sau đó tìm một phần tử không có ngôn ngữ xác định.

Ví dụ, nếu tôi vượt qua trong một miền địa phương của 'en-CA' khi chuyển các dữ liệu trên, tôi muốn có được hai yếu tố sau:

<Translation name="Resource" lang="en-CA">Canadian English Resource</Translation> 
<Translation name="Message" lang="en-CA">Canadian English Message</Translation> 

Nhưng nếu tôi vượt qua trong 'en- GB', tôi muốn có được:

<Translation name="Resource" lang="en-GB">British English Resource</Translation> 
<Translation name="Message" lang="en">English Message</Translation> 

Và cuối cùng nếu tôi vượt qua trong một giá trị như 'es' hoặc 'es-MX', tôi sẽ mong đợi để nhận được:

<Translation name="Resource">Invariant Resource</Translation> 
<Translation name="Message">Invariant Message</Translation> 

Tôi rất mới với XSLT, nhưng tôi nghĩ rằng tôi có một cái gì đó hoạt động. Tôi chỉ cần biết nếu có một cách tốt hơn để làm điều đó (đơn giản, thanh lịch hơn, performant hơn, vv)

Dưới đây là đâm đầu tiên của tôi vào nó:

<?xml version="1.0" encoding="UTF-8" ?> 
<xsl:stylesheet version="1.0" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output encoding="utf-8" indent="yes" method="xml" omit-xml-declaration="yes"/> 

    <xsl:key match="Translation" name="TranslationName" use="concat(@name,':',@lang)"/> 

    <xsl:template match="/"> 
    <!-- locale parameter for translation --> 
    <xsl:param name="locale"/> 

    <xsl:for-each select="Document/Translations/Translation[@lang=$locale or @lang=substring($locale,1,2) or not(@lang)]"> 
     <xsl:choose> 
     <xsl:when test="@lang=$locale and count(key('TranslationName', concat(@name,':',$locale)))=1"> 
      <xsl:element name="p"> 
      <xsl:value-of select="."/> 
      </xsl:element> 
     </xsl:when> 
     <xsl:when test="@lang=substring($locale,1,2) and count(key('TranslationName', concat(@name,':',$locale)))=0"> 
      <xsl:element name="p"> 
      <xsl:value-of select="."/> 
      </xsl:element> 
     </xsl:when> 
     <xsl:when test="not(@lang) and count(key('TranslationName', concat(@name,':',$locale))|key('TranslationName', concat(@name,':',substring($locale,1,2))))=0"> 
      <xsl:element name="p"> 
      <xsl:value-of select="."/> 
      </xsl:element> 
     </xsl:when> 
     </xsl:choose> 
    </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

Đây là lần đầu tiên tôi đến đăng câu hỏi, vì vậy hãy cho tôi biết nếu tôi cần thêm/chỉnh sửa/xóa bất kỳ điều gì.

Cảm ơn!

+0

+1 cho một câu hỏi tốt đầu tiên. –

+0

lưu ý rằng xsl của bạn cho 'en-AU' được đặt trên một tệp chỉ với' en-CA', 'en-GB' và không có' en' sẽ không tạo ra kết quả đầu ra. Câu trả lời của tôi, hy vọng cũng sửa chữa điều này. Sau khi tất cả, họ _can_ hiểu nhau nếu họ thực sự cố gắng, không? –

+0

Trong khi tôi đồng ý, có thể hiểu nhau, yêu cầu của tôi rất rõ ràng về cách họ muốn dự phòng ngôn ngữ hoạt động. Nhưng cảm ơn vì đã bắt được điều đó. – Nick

Trả lời

0

nếu bạn có thể sử dụng msxsl: nút thiết lập hoặc tương tự, bạn có thể làm điều đó thích:

<xsl:template match="/"> 
    <xsl:param name="locale" select="'en-AU'"/> 
<!-- locale parameter for translation --> 
    <xsl:variable name="sorted"> 
     <xsl:for-each select="Document/Translations/Translation"> 
      <xsl:sort select="@name"/> 
      <xsl:sort select="not(@lang=$locale)"/> 
      <xsl:sort select="not(starts-with(@lang, substring($locale,1,2)))"/> 
      <xsl:sort select="@lang"/> 
      <xsl:copy-of select="."/> 
     </xsl:for-each> 
    </xsl:variable> 
    <xsl:for-each select="msxsl:node-set($sorted)/*"> 
     <xsl:if test="position() = 1 or @name!=preceding-sibling::*[1]/@name"> 
      <xsl:copy-of select="."/> 
     </xsl:if> 
    </xsl:for-each> 
</xsl:template> 

T.B. Điều này có thể hoạt động theo tiêu chuẩn 1.0

<xsl:template match="/"> 
    <xsl:param name="locale" select="'en-AU'"/> 
<!-- locale parameter for translation --> 
    <xsl:variable name="path" select="Document/Translations/Translation"/> 
    <xsl:for-each select="$path"> 
     <xsl:variable name="curName" select="$path[@name=current()/@name]"/> 
     <xsl:if test="count($curName[1] | .)=1"> 
      <xsl:for-each select="$curName"> 
      <xsl:sort select="not(@lang=$locale)"/> 
      <xsl:sort select="not(starts-with(@lang, substring($locale,1,2)))"/> 
      <xsl:sort select="@lang"/> 
      <xsl:if test="position()=1"> 
       <xsl:copy-of select="."/> 
      </xsl:if> 
      </xsl:for-each> 
     </xsl:if> 
    </xsl:for-each> 
</xsl:template> 

P.P.S. Nếu bạn không muốn sắp xếp, bạn chỉ có thể thực hiện việc lọc (giữ nguyên thứ tự tài liệu).Ngoài ra, khác với cơ chế phân nhóm:

<xsl:template match="/"> 
    <xsl:param name="locale" select="'en'"/> 
    <xsl:variable name="locale-lang" select="substring($locale,1,2)"/> 
<!-- locale parameter for translation --> 
    <xsl:variable name="path" select="Document/Translations/Translation"/> 
    <xsl:for-each select="$path[not(preceding-sibling::Translation/@[email protected])]"> 
     <xsl:variable name="curName" select="$path[@name=current()/@name]"/> 
     <xsl:variable name="test1" select="$curName[@lang=$locale]"/> 
     <xsl:variable name="test2" select="$curName[@lang=$locale-lang]"/> 
     <xsl:variable name="test3" select="$curName[starts-with(@lang, $locale-lang)]"/> 
     <xsl:variable name="test4" select="$curName[not(@lang)]"/> 
     <xsl:choose> 
      <xsl:when test="$test1"> 
       <xsl:copy-of select="$test1[1]"/> 
      </xsl:when> 
      <xsl:when test="$test2"> 
       <xsl:copy-of select="$test2[1]"/> 
      </xsl:when> 
      <xsl:when test="$test3"> 
       <xsl:copy-of select="$test3[1]"/> 
      </xsl:when> 
      <xsl:when test="$test4"> 
       <xsl:copy-of select="$test4[1]"/> 
      </xsl:when> 
     </xsl:choose> 
    </xsl:for-each> 
</xsl:template> 
+0

Đây là tất cả tuyệt vời! Ngay bây giờ, tôi nghĩ rằng tôi có thể sử dụng một cách tiếp cận lai với các phần từ mỗi. Cảm ơn! – Nick

0

chuyển đổi này ngắn và đơn giản (không có biến, xsl:choose, xsl:when, xsl:otherwise, xsl:if, xsl: sắp xếp, xsl:element):

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

<xsl:param name="pCode" select="'en-GB'"/> 

<xsl:key name="kTransName" match="@name" use="."/> 

<xsl:key name="Resource" match="Translation[@name='Resource']" 
      use="@lang"/> 
<xsl:key name="Message" match="Translation[@name='Message']" 
      use="@lang"/> 
<xsl:key name="Resource" match="Translation[@name='Resource']" 
          use="boolean(@lang)"/> 
<xsl:key name="Message" match="Translation[@name='Message']" 
          use="boolean(@lang)"/> 

<xsl:template match="/"> 

    <xsl:for-each select= 
    "/*/*/*/@name[generate-id()=generate-id(key('kTransName', .)[1])]"> 
     <xsl:copy-of select= 
     "key(., $pCode) 
     | 
     key(., substring($pCode, 1, 2)) 
      [not(key(current(), $pCode))] 
     | 
     key(., 'false') 
      [not(key(current(), $pCode) 
       | 
       key(current(), substring($pCode, 1, 2)) 
      ) 
      ] 
     "/> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 

khi áp dụng trên tài liệu XML được cung cấp:

<Document> 
    <Translations> 
     <Translation name="Resource">Invariant Resource</Translation> 
     <Translation name="Resource" lang="en">English Resource</Translation> 
     <Translation name="Resource" lang="en-CA">Canadian English Resource</Translation> 
     <Translation name="Resource" lang="en-GB">British English Resource</Translation> 
     <Translation name="Message">Invariant Message</Translation> 
     <Translation name="Message" lang="en">English Message</Translation> 
     <Translation name="Message" lang="en-CA">Canadian English Message</Translation> 
     <Translation name="Message" lang="en-AU">Australian English Message</Translation> 
    </Translations> 
</Document> 

tạo ra truy nã, chính xác kết quả:

<Translation name="Resource" lang="en-GB">British English Resource</Translation> 
<Translation name="Message" lang="en">English Message</Translation> 

Nếu chúng ta thay đổi các tham số toàn cầu/bên ngoài để:

<xsl:param name="pCode" select="'en-CA'"/> 

lại kết quả chính xác được sản xuất:

<Translation name="Resource" lang="en-CA">Canadian English Resource</Translation> 
<Translation name="Message" lang="en-CA">Canadian English Message</Translation> 

Nếu chúng ta thay đổi các tham số toàn cầu/bên ngoài để:

<xsl:param name="pCode" select="'es-MX'"/> 

lại kết quả mong muốn được sản xuất:

<Translation name="Resource">Invariant Resource</Translation> 
<Translation name="Message">Invariant Message</Translation> 
+0

Cảm ơn bạn đã trả lời, nhưng tiếc là sẽ có nhiều giá trị có thể có cho @name khác hơn là "Tài nguyên" và "Thư". Tôi đoán tôi nên làm điều đó rõ ràng hơn một chút trong câu hỏi. – Nick

Các vấn đề liên quan