/ / Dopełnienie znaków XSLT dla znaków europejskich do stałej szerokości wyjściowej - xml, xslt, kodowanie znaków

Dopełnienie znaków XSLT dla znaków europejskich do stałej szerokości wyjściowej - xml, xslt, kodowanie znaków

Mam wymóg, aby wziąć trochę XML iprzekształcić go w plik ładowania o stałej szerokości w celu załadowania do systemu SAP. Mój algorytm działa dobrze, z wyjątkiem niektórych dziwnych postaci europejskich, takich jak Ã, które, gdy w ciągu zwraca wartość ciągu +1, dla każdego wystąpienia znaku. Na przykład tekst Ãbcd miałby długość łańcucha (wartość $) 5 zamiast 4.

To jest problem, ponieważ mój kod sprawdzajaka jest długość właściwości, a następnie odejmuje ją od maksymalnej długości formatu wyjściowego o stałej długości (tj. dla pola o szerokości 30, jeśli odczyta Ãbcd, wydaje się, że potrzebuje 25 pól zamiast 26).

Czy ktoś wie o lepszy sposób to zrobić, lub co robię źle w moim algorytmie?

Poniżej znajdują się moje szablony xsl (w przeważającej części ... nie można ich tu całkiem poprawnie ...)

Szablon do napisania własności:

<xsl:param name="value"/>
<xsl:param name="width"/>

<!-- find the current length of the field-->
<xsl:variable name="valueWidth" select="string-length($value)" />
<xsl:variable name="difference" select="$width - $valueWidth" />


<xsl:if test="$difference &gt; 0">
<xsl:value-of select="$value"/>
<!-- run this for loop x times outputing space for each -->
<xsl:call-template name="for-loop-spaces">
<xsl:with-param name="count" select="$difference - 1" />
</xsl:call-template>

</xsl:if>


<xsl:if test="($difference &lt; 0)">
<xsl:value-of select="substring($value,0,$width)"/>
</xsl:if>

<xsl:if test="$difference = 0">
<xsl:value-of select="$value"/>
</xsl:if>
</xsl:template>

For-loop-spaces template (nie skopiuje i nie wklei): wyprowadza spację za każdym razem, gdy jest wywoływana, akceptuje parametr "licznik" .Jeśli liczba jest większa od zera, wywołaj rekursywnie z count-1 do 0.

Wszelkie dane wejściowe byłyby bardzo przydatne :)

Odpowiedzi:

2 dla odpowiedzi № 1

Problem polega na tym, że zamiast znaków pojedynczych można użyć kombinacji znaków diakrytycznych. To daje ci "złą długość".

Widzieć http://en.wikipedia.org/wiki/Combining_character aby uzyskać więcej informacji na temat tych znaków.

Jeśli masz XSLT 2, istnieje wbudowana funkcja normalizacji, która powinna działać: fn: normalize-unicode

W przypadku XSLT 1.0 będziesz musiał użyć jakiejś funkcji, aby zliczyć znaki wykluczając kombinację znaków. Jedną z możliwości może być użycie translate:

translate($input, "&#768;&#769;&#770;&#771;&#772;&#773;&#774;&#775;&#776;&#777;&#778;&#779;&#780;&#781;&#782;&#783;&#784;&#785;&#786;&#787;&#788;&#789;&#790;&#791;&#792;&#793;&#794;&#795;&#796;&#797;&#798;&#799;&#800;&#801;&#802;&#803;&#804;&#805;&#806;&#807;&#808;&#809;&#810;&#811;&#812;&#813;&#814;&#815;&#816;&#817;&#818;&#819;&#820;&#821;&#822;&#823;&#824;&#825;&#826;&#827;&#828;&#829;&#830;&#831;&#832;&#833;&#834;&#835;&#836;&#837;&#838;&#839;&#840;&#841;&#842;&#843;&#844;&#845;&#846;&#847;&#848;&#849;&#850;&#851;&#852;&#853;&#854;&#855;&#856;&#857;&#858;&#859;&#860;&#861;&#862;&#863;&#864;&#865;&#866;&#867;&#868;&#869;&#870;&#871;&#872;&#873;&#874;&#875;&#876;&#877;&#878;&#879;", "")

Zauważ, że będziesz mieć więcej problemów, jeśli masz połączone znaki azjatyckie.

Cytat z http://www.dpawson.co.uk/xsl/characters.html

Jednak jeśli kombinacja Unicode postać jestużywany i plik wejściowy ma e "(gdzie" jest naprawdę łącząc ostry charakter), a następnie podczas każdy renderer świadomy Unicode ma sprawić, żeby stało się to ostre renderowanie do silnika XML to dwa postacie, e i ostre.


2 dla odpowiedzi nr 2

string-length(), podobnie jak wszystkie XSLT / XPath, opiera się na znakach, a nie na bajtach, więc string-length("Ãbcd") zdecydowanie powinien dać 4. Jeśli daje 5 to albo:

  • Twój à to właściwie dwie oddzielne postacie, jedna z nichkombinacja tyldy diakrytycznej, i jest rzeczywiście poprawna, nawet jeśli oznacza kolumny nie wizualnie wyrównane. Ale zgaduję, że nie, ponieważ wersja, którą tu wkleiłeś, jest pojedynczą, złożoną postacią, U + 00C3 LATIN CAPITAL LETTER A WITH TILDE.

  • Twój wejściowy kod XML został odczytany z błędemkodowanie, w rzeczywistości będące w utf-8 (domyślne dla XML), ale odczytane jako coś innego, zwykle ISO-8859-1, czyniąc znak U + 00C3, reprezentowany przez sekwencję bajtów 0xC3,0x83, wychodzą jako dwa znaki U + 00C3, U + 0083 (Ã).

Nie chodzi tylko o "dziwne postacie z Europy", o które musisz się martwić, jeśli otrzymujesz Unicode źle wszystko postacie spoza podstawowego 7-bitowego zestawu ASCII zostaną zniekształcone, w tym wiele, które nawet wyspiarscy Amerykanie lubią używać.

W każdym razie jest pytanie, jakie kodowanie chce SAP dla jego formatu wejściowego FWV. To wszystko bardzo dobrze traktuje à jako pojedynczy znak i dodawanie odpowiedniej liczby znaków dopełniających dla jednego znaku, ale jeśli następnie wyświetlisz wynik do UTF-8, a SAP nie odczyta jeszcze pliku utf-8, to nadal będzie łamał import.

Będziesz musiał znaleźć kodowanie oczekiwane przez docelową instalację SAP (jeśli to nie utf-8, cp1252 to kolejny dobry sposób na wypróbowanie) i czy stałe kolumny w formacie są oparte na znakach Unicode lub bajtach. Z tego (powiązane?) spec Sądzę, że faktycznie są oparte na bajtach, w którym to przypadku 5 faktycznie byłby prawidłową długością bajtu, jeśli twoja baza ma zawierać utf-8.

Niestety, XSLT dotyczy znaków i nie daje możliwości pracy z bajtami, więc jeśli plik wejściowy jest oparty na bajtach, będziesz musiał:

  • usuń wszystkie znaki spoza ASCII, tworząc punkt sporny, lub

  • użyj innego narzędzia poza XSLT, aby to zrobićprzetwarzanie, które zna bajty. Szczerze mówiąc to ma dla mnie największy sens: XSLT jest idealny do transformacji XML-do-XML i w dużej mierze okropny dla innych zadań związanych z przetwarzaniem ciągów. Powyższy szablon może być bardziej czytelny i efektywny ponownie napisany w kilku liniach nowoczesnego języka skryptowego, takiego jak Python.


0 dla odpowiedzi № 3

Czy liczą się bajty lub znaki? The à wspomniałeś, że jest 1 znak, ale 2 bajty (gdy używasz utf-8, co wydaje się być w tym przypadku). Znaki w utf-8 mogą zajmować 1-4 bajty.

Jeśli długość łańcucha liczy bajty, wynik jest poprawny.


0 dla odpowiedzi nr 4

To nie jest problem XSLT, ale prawdopodobnie problem z kodowaniem wyjścia. W jaki sposób jest wykonywany Twój XSLT? Prawdopodobnie będziesz musiał zmienić ustawienia nagrywarki wyjściowej.

Jak zauważył Oded, może to być problem z kodowaniem czytnika wejściowego, a nie z kodowaniem wyjściowym, ponieważ, zgodnie z Specyfikacja XPathciąg znaków liczy znaki, więc możesz byćzliczanie znaków ciągu skonwertowanego na więcej niż jeden znak dla Ę. Może wejście to utf-8, ale twoja konfiguracja odczytuje go jako kodowanie pojedynczego bajtu?