2016-01-23 57 views
1

我正在为Oracle编写一个PL/SQL工具来从游标中获取XML Spreadsheet。如何使用XSLT 1.0将UTF8 4位数表示转换回原始字符集?

几天后,我得出结论:完成它的最简单方法只是传递Oracle DB提供的XML功能。

所以,我的想法是将查询结果格式化为XML格式,然后通过XSLT获取Excel电子表格。

到目前为止,这么好:我设法从我写的查询中获得电子表格,但我需要解决一个小问题。

我希望能够在Excel中设置列标题只是在我的列上设置别名,但是当我使用不符合XML语言的字符时,我显然会得到与我的意思不同的东西。

select dbms_xmlgen.getxmltype(
'select first_name as "First na/Me" 
    from hr.employees 
    where department_id = 100;') from dual; 

产生:

<ROWSET> 
<ROW> 
    <First_x0020_na_x002F_Me>Nancy</First_x0020_na_x002F_Me> 
</ROW> 
<ROWSET> 

没有什么能阻止我获得我的Excel,虽然,我然后通过XSLT转换上面的XML文档到Excel 2007兼容的工作簿包含此节点

<Cell> 
<Data ss:Type="String">First_x0020_na_x002F_Me</Data> 
</Cell> 

在这一点上,我只需要在列标题中指示我的XSLT ti搜索“x \ uFFFF”,提取十六进制代码并把它变成相应的角色,但是怎么做呢?

正如在标题中提到的,我的XSLT符合1.0.1 ,但我可以根据需要升级到较高版本 ,由于Oracle DB中的XSLT 2.0不支持本地支持,因此我无法升级。

+0

“*我的XSLT是1.0兼容的,但可以升级*”我相信你会使用XSLT 2.0,它支持了'码点到字符串()'功能更快乐(以及其他功能,使串处理更容易)。 –

+0

我会看看,看看我能不能完成任务。 – Max

+0

@Max我应该补充说,*可以在XSLT 1.0中完成 - 只要你有一个可能需要恢复的字符的有限列表。但是如果没有正则表达式支持的话,它仍然会相当尴尬。 –

回答

1

在这一点上我只需要指示我的XSLT列搜索 标题为“X \ uFFFF”,提取的十六进制代码,并把它变成 相应的字符,但如何才能做到这一点?

正如在标题中提到的,我的XSLT符合1.0,但如果需要,可以将 升级到较高版本。

此XSLT 2.0转化

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my"> 
<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()[matches(., '_x(\d|[A-Fa-f]){4}_')]"> 
    <xsl:analyze-string select="." regex="_x((\d|[A-Fa-f]){{4}})_" > 
     <xsl:matching-substring> 
     <xsl:value-of select="codepoints-to-string(my:hex-to-int(regex-group(1), 0))"/> 
     </xsl:matching-substring> 
     <xsl:non-matching-substring><xsl:value-of select="."/></xsl:non-matching-substring> 
    </xsl:analyze-string> 
    </xsl:template> 

    <xsl:function name="my:hex-to-int" as="xs:integer"> 
    <xsl:param name="pHex" as="xs:string"/> 
    <xsl:param name="pResult" as="xs:integer"/> 

    <xsl:sequence select= 
    "if(not($pHex)) 
     then $pResult 
     else 
     my:hex-to-int(substring($pHex, 2), 
         16*$pResult + my:hex-digit-to-int(substring($pHex, 1, 1))) 
    "/> 
    </xsl:function> 

    <xsl:function name="my:hex-digit-to-int" as="xs:integer"> 
    <xsl:param name="pHexDigit" as="xs:string"/> 

    <xsl:sequence select= 
     "index-of(string-to-codepoints('abcdef'), 
       string-to-codepoints(lower-case($pHexDigit)))[1] -1"/> 
    </xsl:function> 
</xsl:stylesheet> 

当所提供的XML文档施加:

<Cell xmlns:ss="some:ss"> 
    <Data ss:Type="String">First_x0020_na_x002F_Me</Data> 
</Cell> 

产生想要的,正确的结果

<Cell xmlns:ss="some:ss"> 
     <Data ss:Type="String">First na/Me</Data> 
</Cell> 

注意

在XSLT 1.0类似的解决方案将是可能的,如果我们可以使用一个扩展功能,它接受一个整数,并返回作为其代码这个整数的Unicode字符 - 正是XPath 2.0 codepoints-to-string()功能正在做。

至于逃避 “不安全的HTML字符”,只是规定:

<xsl:output method="html"/> 

<xsl:output method="xhtml"/> 

应确保不安全的字符适当的代表。

+0

这本来很好,但不幸的是我发现XSLT 2.0并不是Oracle本地支持的,所以我不能依靠你的真棒解决方案。此外,我只是意识到我的最初要求是不正确的:如果在字符串中出现“<”符号怎么办?这需要逃避。我不知道你的解决方案将如何处理(我没有测试过)。顺便说一下,我正在关闭这个帖子,接受你的解决方案是否适合这个问题。 – Max

+0

@Max,无论何时您进一步发展您的需求,我都很乐意为您提供帮助。 –

+0

@Max,Re:“如果在字符串中出现一个”<“符号呢?这需要被转义。”如果您可以使用XPath 2.0(XSLT 2.0),则有标准的XPath函数:** escape-html-uri()**,** http://w3.org/TR/xpath-functions/#func- escape-html-uri **和这个函数,除其他外,转义不安全的(对于HTML)字符。或者,如果输出方法为“html”,则可能不需要这样的转义 - 这应该通过XSLT序列化完成。另外,如果这些字符出现在您的源XML文档中,那么它们中的一些或全部将已经被转义,正如格式良好的XML的词法规则所要求的那样 –