[英]Using XSLT to create a PLSQL statement to output XML
我已經在互聯網上搜索了一種工具來執行此操作,但我沒有找到一個工具,因此我認為創建自己應該很簡單。 我想創建一個XSLT,在其中輸入任意xml文件,它將輸出一個select語句,可以在Oracle數據庫內部使用該語句來生成輸入xml。
例如,如果我給它:
<?xml version="1.0"?>
<test xmlns="dddd" xmlns:xxx="ddd222" someatt="val">
<xxx:f>E</xxx:f>
<g>G</g>
<h xmlns="anotherns">H</h>
<zz:i xmlns:zz="yetanotherns">I</zz:i>
</test>
我想要以下輸出:
select
xmlelement("test"
,xmlattributes(
'dddd' as "xmlns"
,'ddd222' as "xmlns:xxx"
,'val' as "someatt"
)
,xmlelement("xxx:f",'E')
,xmlelement("g",'G')
,xmlelement("h"
,xmlattributes('anotherns' as "xmlns")
,'H'
)
,xmlelement("zz:i"
,xmlattributes('yetanotherns' as "xmlns:zz")
,'I'
)
)
from dual;
我幾乎一直都在那兒。 我可以使用當前的XSLT進行以下輸出:
select
xmlelement("test"
,xmlattributes(
'val' as "someatt"
)
,xmlelement("xxx:f",'E')
,xmlelement("g",'G')
,xmlelement("h",'H')
,xmlelement("zz:i",'I')
)
from dual;
除了缺少xmlns屬性之外,這是完美的。 問題是輸入文檔中的xmlns和xmlns:***屬性沒有被視為普通屬性,並且在運行xslt時似乎不可見。 是否可以保留他們?
我擁有的xslt如下:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
>
<xsl:output method="text" indent="no" omit-xml-declaration="yes" />
<xsl:template match="/">
<xsl:text>select
</xsl:text>
<xsl:apply-templates/>
<xsl:text>
from dual;</xsl:text>
</xsl:template>
<xsl:template match="node()">
<xsl:text>xmlelement("</xsl:text>
<xsl:value-of select='name()'/>
<xsl:text>"</xsl:text>
<!--Lots of tabs for indenting-->
<xsl:variable name='tabs' xml:space="preserve"> </xsl:variable>
<xsl:variable name='nl'><xsl:text>
</xsl:text><xsl:value-of select='substring($tabs,0,count(ancestor::*)+2)'/></xsl:variable>
<xsl:variable name='att_children' select='count(@*)'/>
<xsl:if test="$att_children > 0">
<xsl:value-of select="$nl"/>
<xsl:text>,xmlattributes(</xsl:text>
<xsl:for-each select='./@*'>
<xsl:value-of select="$nl"/><xsl:text> </xsl:text>
<xsl:if test="position() > 1"><xsl:text>,</xsl:text></xsl:if>
<xsl:text>'</xsl:text>
<xsl:value-of select="."/>
<xsl:text>' as "</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>"</xsl:text>
</xsl:for-each>
<xsl:value-of select="$nl"/>
<xsl:text>)</xsl:text>
</xsl:if>
<xsl:variable name='children' select='count(*)'/>
<!--<xsl:value-of select='$children'/>-->
<xsl:choose>
<xsl:when test='$children=0'>
<xsl:text>,</xsl:text>
<xsl:text>'</xsl:text>
<xsl:value-of select='text()'/>
<xsl:text>'</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select='./*'>
<xsl:value-of select="$nl"/>
<xsl:text>,</xsl:text>
<xsl:apply-templates select='.'/>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
<xsl:if test='$children > 1'>
<xsl:value-of select="$nl"/>
</xsl:if>
<xsl:text>)</xsl:text>
</xsl:template>
<xsl:template match="text()|@*"> </xsl:template>
</xsl:stylesheet>
我只有一部分解決您的問題。
除了屬性,它首先包括計算要輸出的名稱空間:
<xsl:variable name='att_children' select='count(@* | namespace::*[not(name() = "xml")])'/>
然后還循環在您的節點上定義的名稱空間(有一個額外的謂詞可以避免使用默認的xml名稱空間):
<xsl:if test="$att_children > 0">
<xsl:value-of select="$nl"/>
<xsl:text>,xmlattributes(</xsl:text>
<xsl:for-each select='./@* | namespace::*[not(name() = "xml")]'>
<xsl:value-of select="$nl"/><xsl:text> </xsl:text>
<xsl:if test="position() > 1"><xsl:text>,</xsl:text></xsl:if>
<xsl:text>'</xsl:text>
<xsl:value-of select="."/>
<xsl:text>' as "</xsl:text>
<xsl:choose>
<!-- for real attributes -->
<xsl:when test="self::attribute">
<xsl:value-of select="name()"/>
</xsl:when>
<!-- for namespaces -->
<xsl:otherwise>
<xsl:choose>
<xsl:when test='name() = ""'>xmlns</xsl:when>
<xsl:otherwise>
<xsl:text>xmlns:</xsl:text>
<xsl:value-of select="name()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
<xsl:text>"</xsl:text>
</xsl:for-each>
<xsl:value-of select="$nl"/>
<xsl:text>)</xsl:text>
</xsl:if>
這是我到目前為止獲得的:
select
xmlelement("test"
,xmlattributes(
'dddd' as "xmlns"
,'ddd222' as "xmlns:xxx"
,'val' as "xmlns:someatt"
)
,xmlelement("xxx:f"
,xmlattributes(
'dddd' as "xmlns"
,'ddd222' as "xmlns:xxx"
),'E')
,xmlelement("g"
,xmlattributes(
'dddd' as "xmlns"
,'ddd222' as "xmlns:xxx"
),'G')
,xmlelement("h"
,xmlattributes(
'anotherns' as "xmlns"
,'ddd222' as "xmlns:xxx"
),'H')
,xmlelement("zz:i"
,xmlattributes(
'dddd' as "xmlns"
,'ddd222' as "xmlns:xxx"
,'yetanotherns' as "xmlns:zz"
),'I')
)
from dual;
限制是繼承的名稱空間在每個元素上重復。 它有些多余,但通常不會影響有效的XML。
不幸的是,我無法找到一種方法來檢查命名空間是否已經在祖先元素上定義,以避免這種重復。
我不確定您能否完全得到您想要的。 namespace::
軸將返回對節點有效的所有名稱空間,不一定返回聲明該名稱空間的時間(該名稱空間可能是祖先節點)
您可以做的是使用以下表達式,嘗試檢查XML中第一次出現名稱空間前綴和uri。
<xsl:for-each select="namespace::*[name() != 'xml']">
<xsl:if test="not(../ancestor::*/namespace::*[. = current()/. and name() = current()/name()])">
嘗試使用此XSLT(可能需要對輸出的格式進行一些工作)
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
>
<xsl:output method="text" indent="no" omit-xml-declaration="yes" />
<xsl:template match="/">
<xsl:text>select
</xsl:text>
<xsl:apply-templates/>
<xsl:text>
from dual;</xsl:text>
</xsl:template>
<xsl:template match="node()">
<xsl:text>xmlelement("</xsl:text>
<xsl:value-of select='name()'/>
<xsl:text>"</xsl:text>
<!--Lots of tabs for indenting-->
<xsl:variable name='tabs' xml:space="preserve"> </xsl:variable>
<xsl:variable name='nl'><xsl:text>
</xsl:text><xsl:value-of select='substring($tabs,0,count(ancestor::*)+2)'/></xsl:variable>
<xsl:variable name="namespaces">
<xsl:if test="self::*">
<xsl:for-each select="namespace::*[name() != 'xml']">
<xsl:if test="not(../ancestor::*/namespace::*[. = current()/. and name() = current()/name()])">
<xsl:text>,'</xsl:text>
<xsl:value-of select="." />
<xsl:text>' as "xmlns</xsl:text>
<xsl:if test="name() != ''">
<xsl:text>:</xsl:text>
<xsl:value-of select="name()" />
</xsl:if>
<xsl:text>"</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:if>
</xsl:variable>
<xsl:variable name='att_children' select='count(@*)'/>
<xsl:if test="$att_children > 0 or $namespaces != ''">
<xsl:value-of select="$nl"/>
<xsl:text>,xmlattributes(</xsl:text>
<xsl:value-of select="substring($namespaces, 2)" />
<xsl:for-each select='./@*'>
<xsl:value-of select="$nl"/><xsl:text> </xsl:text>
<xsl:if test="position() > 1 or $namespaces != ''"><xsl:text>,</xsl:text></xsl:if>
<xsl:text>'</xsl:text>
<xsl:value-of select="."/>
<xsl:text>' as "</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>"</xsl:text>
</xsl:for-each>
<xsl:value-of select="$nl"/>
<xsl:text>)</xsl:text>
</xsl:if>
<xsl:variable name='children' select='count(*)'/>
<!--<xsl:value-of select='$children'/>-->
<xsl:choose>
<xsl:when test='$children=0'>
<xsl:text>,</xsl:text>
<xsl:text>'</xsl:text>
<xsl:value-of select='text()'/>
<xsl:text>'</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select='./*'>
<xsl:value-of select="$nl"/>
<xsl:text>,</xsl:text>
<xsl:apply-templates select='.'/>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
<xsl:if test='$children > 1'>
<xsl:value-of select="$nl"/>
</xsl:if>
<xsl:text>)</xsl:text>
</xsl:template>
<xsl:template match="text()|@*"> </xsl:template>
</xsl:stylesheet>
在您將名稱空間前綴重新定義為其他URI,然后將其重新定義為原始URI的情況下,這可能不起作用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.