簡體   English   中英

使用XSLT創建PLSQL語句以輸出XML

[英]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 &gt; 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() &gt; 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 &gt; 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 &gt; 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() &gt; 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 &gt; 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() &gt; 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 &gt; 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM