2015-06-16 38 views
0

我已經在網上搜索了一個工具來做到這一點,但我還沒有找到一個,所以我認爲創建自己應該很簡單。 我想創建一個XSLT,我輸入一個任意的xml文件,它會輸出一個select語句,我可以在Oracle數據庫中使用它來生成輸入xml。使用XSLT創建一個PLSQL語句來輸出XML

E.g. 如果我給它:

<?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> 
+1

'xmlns'不是一個屬性,它是一個名稱空間聲明。您仍然可以在XSLT中訪問它們,但是您可能需要了解如何在PLSQL/Oracle中處理XML名稱空間,以便您知道首先要生成的輸出,因爲它可能與您當前顯示的預期輸出不同。 –

+0

@TimC似乎(奇怪)它是定義屬性或名稱空間的函數,請參閱http://stackoverflow.com/questions/437670/oracle-how-to-create-an-element-in-a-specific-namespace-with-xmlelement – potame

+0

嗨,是的,我知道什麼輸出我想從xslt,它是在問題中。 PLSQL將xmlns視爲正常的屬性,並且我已經在這個問題中測試了這個語句並且它可以工作。 – Robert3452

回答

1

我只有解決您的問題的一部分。

它由首先,計數的命名空間是輸出,除了屬性:

<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。

不幸的是,我不能找到一種方法來檢查名稱空間是否已經定義在祖先元素上,以避免這種重複。

+0

是的,謝謝你看這個。重新計算名稱空間是一種選擇,但它變得非常複雜。我希望使用與輸入文檔相同的名稱空間前綴,但可能會在樹的不同級別使用相同的前綴。也有可能相同的名稱空間使用不同的前綴。我考慮將文檔中的所有命名空間一起收集起來並在頂層輸出它們,但它可能會破壞事情。按照在輸入文檔中完全複製聲明的規則應該更簡單。 – Robert3452

0

我不確定你是否能夠得到你確切的結果。 namespace::軸將返回所有對節點有效的名稱空間,不一定在聲明該名稱空間時(可能是祖先節點)

您可以做的是使用以下表達式來嘗試並檢查第一個時間一個命名空間前綴和URI出現在XML

<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。