0

xml から SQL データを抽出するための提案を教えてください。サンプル xml は、CLOB としてプロシージャへの入力として次のようになります。

<filter>
  <and>
    <or>
      <equals field="MARKET_NAME" value="Chicago"/>
      <equals field="MARKET_NAME" value="BOSTON"/>
    </or>
    <or>
      <equals field="RANK" value="1"/>
      <equals field="RANK" value="2"/>
    </or>
    <between field="current_data" arg1="start_date" arg2="End_date"/>
    <gt field="CUME" value="20"/>
    <like field="DMA_NAME" value="%ABC%"/>
  </and>
</filter>

抽出されたデータは次のようになります。

(MARKET_NAME = 'Chicago' or MARKET_NAME = 'BOSTON') and 
(RANK = 1 or RANK = 2) and 
(current_date between start_date and End_Date) and 
CUME > 20 and 
DMA_NAME like '%ABC%'

貴重なヒントを教えてください..

前もって感謝します

4

1 に答える 1

2

1 つのアプローチは、XSL スタイルシートです。

しかし、私はあなたのXMLデータ型に追加します. 例えば

<filter>
    <and>
        <or>
            <equals field="MARKET_NAME" value="Chicago" datatype="string"/>
            <equals field="MARKET_NAME" value="BOSTON" datatype="string"/>
        </or>
        <or>
            <equals field="RANK" value="1" datatype="number"/>
            <equals field="RANK" value="2" datatype="number"/>
        </or>
        <between field="current_data" arg1="start_date" arg2="End_date" datatype="field"/>
        <between field="foo" arg1="20121230" arg2="20130101 01:12:23" datatype="date"/>
        <gt field="CUME" value="20" datatype="number"/>
        <like field="DMA_NAME" value="%ABC%"  datatype="string"/>
    </and>
</filter>

次に、XSL (これは単なるサンプルです。これは基本的なスターターにすぎないため、これを改善する必要があります!)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
    exclude-result-prefixes="xd"
    version="1.0">
    <xsl:output method="text"/>

    <xsl:template name="string-replace-all">
        <xsl:param name="text"/>
        <xsl:param name="replace"/>
        <xsl:param name="by"/>
        <xsl:choose>
            <xsl:when test="contains($text,$replace)">
                <xsl:value-of select="substring-before($text,$replace)"/>
                <xsl:value-of select="$by"/>
                <xsl:call-template name="string-replace-all">
                    <xsl:with-param name="text" select="substring-after($text,$replace)"/>
                    <xsl:with-param name="replace" select="$replace"/>
                    <xsl:with-param name="by" select="$by"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$text"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template name="processDatatype">
        <xsl:param name="value" />
        <xsl:param name="datatype" />
        <xsl:choose>
            <xsl:when test="$datatype = 'string'">
                <xsl:text>&apos;</xsl:text>
                <xsl:call-template name="string-replace-all">
                    <xsl:with-param name="text" select="$value"/>
                    <xsl:with-param name="replace" select='"&apos;"'/>
                    <xsl:with-param name="by" select='"&apos;&apos;"'/>
                </xsl:call-template>
                <xsl:text>&apos;</xsl:text>
            </xsl:when>
            <xsl:when test="$datatype = 'date'">
                <xsl:text>to_date(&apos;</xsl:text>
                <xsl:value-of select="$value"/>
                <xsl:text>&apos;,&apos;yyyymmdd hh24:mi:ss&apos;)</xsl:text>
            </xsl:when>
            <xsl:otherwise><xsl:value-of select="$value"/></xsl:otherwise>
        </xsl:choose>

    </xsl:template>

    <xsl:template name="gt">
        <xsl:value-of select="@field"/>
        <xsl:text> &gt; </xsl:text>
        <xsl:call-template name="processDatatype">
            <xsl:with-param name="value"><xsl:value-of select="@value"/></xsl:with-param>
            <xsl:with-param name="datatype"><xsl:value-of select="@datatype"/></xsl:with-param>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="lt">
        <xsl:value-of select="@field"/>
        <xsl:text> &lt; </xsl:text>
        <xsl:call-template name="processDatatype">
            <xsl:with-param name="value"><xsl:value-of select="@value"/></xsl:with-param>
            <xsl:with-param name="datatype"><xsl:value-of select="@datatype"/></xsl:with-param>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="between">
        <xsl:value-of select="@field"/>
        <xsl:text> between </xsl:text>
        <xsl:call-template name="processDatatype">
            <xsl:with-param name="value"><xsl:value-of select="@arg1"/></xsl:with-param>
            <xsl:with-param name="datatype"><xsl:value-of select="@datatype"/></xsl:with-param>
        </xsl:call-template>
        <xsl:text> and </xsl:text>
        <xsl:call-template name="processDatatype">
            <xsl:with-param name="value"><xsl:value-of select="@arg2"/></xsl:with-param>
            <xsl:with-param name="datatype"><xsl:value-of select="@datatype"/></xsl:with-param>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="like">
        <xsl:value-of select="@field"/>
        <xsl:text> like </xsl:text>
        <xsl:call-template name="processDatatype">
            <xsl:with-param name="value"><xsl:value-of select="@value"/></xsl:with-param>
            <xsl:with-param name="datatype"><xsl:value-of select="@datatype"/></xsl:with-param>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="equals">
        <xsl:value-of select="@field"/>
        <xsl:text> = </xsl:text>
        <xsl:call-template name="processDatatype">
            <xsl:with-param name="value"><xsl:value-of select="@value"/></xsl:with-param>
            <xsl:with-param name="datatype"><xsl:value-of select="@datatype"/></xsl:with-param>
        </xsl:call-template>
    </xsl:template>


    <xsl:template name="and">
        <xsl:for-each select="*">
            <xsl:if test="position() != 1">
                <xsl:text>and </xsl:text>
            </xsl:if>
            <xsl:choose>
                <xsl:when test="name() = 'like'">
                    <xsl:text>(</xsl:text>
                    <xsl:call-template name="like" />
                    <xsl:text>)&#10;</xsl:text>
                </xsl:when>
                <xsl:when test="name() = 'gt'">
                    <xsl:text>(</xsl:text>
                    <xsl:call-template name="gt" />
                    <xsl:text>)&#10;</xsl:text>
                </xsl:when>
                <xsl:when test="name() = 'lt'">
                    <xsl:text>(</xsl:text>
                    <xsl:call-template name="lt" />
                    <xsl:text>)&#10;</xsl:text>
                </xsl:when>
                <xsl:when test="name() = 'equals'">
                    <xsl:text>(</xsl:text>
                    <xsl:call-template name="equals" />
                    <xsl:text>)&#10;</xsl:text>
                </xsl:when>
                <xsl:when test="name() = 'between'">
                    <xsl:text>(</xsl:text>
                    <xsl:call-template name="between" />
                    <xsl:text>)&#10;</xsl:text>
                </xsl:when>
                <xsl:when test="name() = 'or'">
                    <xsl:text>(</xsl:text>
                    <xsl:call-template name="or" />
                    <xsl:text>)&#10;</xsl:text>
                </xsl:when>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="or">
        <xsl:for-each select="*">
            <xsl:if test="position() != 1">
                <xsl:text>or </xsl:text>
            </xsl:if>
            <xsl:choose>
                <xsl:when test="name() = 'like'">
                    <xsl:text>(</xsl:text>
                    <xsl:call-template name="like" />
                    <xsl:text>)&#10;</xsl:text>
                </xsl:when>
                <xsl:when test="name() = 'gt'">
                    <xsl:text>(</xsl:text>
                    <xsl:call-template name="gt" />
                    <xsl:text>)&#10;</xsl:text>
                </xsl:when>
                <xsl:when test="name() = 'lt'">
                    <xsl:text>(</xsl:text>
                    <xsl:call-template name="lt" />
                    <xsl:text>)&#10;</xsl:text>
                </xsl:when>
                <xsl:when test="name() = 'equals'">
                    <xsl:text>(</xsl:text>
                    <xsl:call-template name="equals" />
                    <xsl:text>)&#10;</xsl:text>
                </xsl:when>
                <xsl:when test="name() = 'between'">
                    <xsl:text>(</xsl:text>
                    <xsl:call-template name="between" />
                    <xsl:text>)&#10;</xsl:text>
                </xsl:when>
                <xsl:when test="name() = 'and'">
                    <xsl:text>(</xsl:text>
                    <xsl:call-template name="and" />
                    <xsl:text>)&#10;</xsl:text>
                </xsl:when>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>

    <xsl:template match="/filter">
        <xsl:text>where </xsl:text>
        <xsl:for-each select="*">
            <xsl:choose>
                <xsl:when test="name() = 'and'">
                    <xsl:call-template name="and" />
                </xsl:when>
                <xsl:when test="name() = 'or'">
                    <xsl:call-template name="or" />
                </xsl:when>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

例:

XMLTYPE として格納されている XSL:

SQL> select * from xsl;

NAME
--------------------
XSL
--------------------------------------------------------------------------------
xml_to_sql
<?xml version="1.0" encoding="WINDOWS-1252"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http:
//www.oxygenxml.com/ns/doc/xsl" exclude-result-prefixes="xd" version="1.0">
  <xsl:output method="text"/>
  <xsl:template name="string-replace-all">
    <xsl:param name="text"/>
...

transformここで、入力 XML に対して XMLTYPE 関数を使用して結果を取得します。

SQL> select dbms_xmlgen.convert(xmltype('<?xml-stylesheet type="text/xsl" href="test.xsl"?>
  2  <filter>
  3      <and>
  4          <or>
  5              <equals field="MARKET_NAME" value="Chicago" datatype="string"/>
  6              <equals field="MARKET_NAME" value="BOSTON" datatype="string"/>
  7          </or>
  8          <or>
  9              <equals field="RANK" value="1" datatype="number"/>
 10              <equals field="RANK" value="2" datatype="number"/>
 11          </or>
 12          <between field="current_data" arg1="start_date" arg2="End_date" datatype="field"/>
 13          <between field="foo" arg1="20121230" arg2="20130101 01:12:23" datatype="date"/>
 14          <gt field="CUME" value="20" datatype="number"/>
 15          <like field="DMA_NAME" value="%AB&apos;C%"  datatype="string"/>
 16      </and>
 17  </filter>').transform(xsl.xsl).getclobval(), 1)
 18  from xsl
 19  /

DBMS_XMLGEN.CONVERT(XMLTYPE('<
--------------------------------------------------------------------------------
where ((MARKET_NAME = 'Chicago')
or (MARKET_NAME = 'BOSTON')
)
and ((RANK = 1)
or (RANK = 2)
)
and (current_data between start_date and End_date)
and (foo between to_date('20121230','yyyymmdd hh24:mi:ss') and to_date('20130101
 01:12:23','yyyymmdd hh24:mi:ss'))
and (CUME > 20)
and (DMA_NAME like '%AB''C%')
于 2013-01-02T10:50:33.227 に答える