如何编写一个 PL/SQL 程序来打印出看起来像 xml 格式的字符串

Posted

技术标签:

【中文标题】如何编写一个 PL/SQL 程序来打印出看起来像 xml 格式的字符串【英文标题】:How write a PL/SQL program that prints out string which looking like xml format 【发布时间】:2017-07-14 07:49:42 【问题描述】:

输入字符串:“a4b4c2d9d9c2e6e6b4s2o1o1s2a4w2r8r8k3g5g5k3w2” 我尝试了此代码作为第一步:

declare
   word varchar2(50)  := 'a4b4c2d9d9c2e6e6b4s2o1o1s2a4w2r8r8k2g5g5k2w2';
   num  number        := length(word)/2;
   name_array dbms_sql.varchar2_table;
begin
   dbms_output.put_line(word);
   FOR i IN 1..num LOOP
      name_array(i) := substr(word, -2*i, 2);
   END LOOP;
   FOR i IN name_array.FIRST .. name_array.LAST LOOP
      dbms_output.put_line(name_array(i));
   END LOOP;
end;

此代码仅创建一个字符串数组。不是xml格式。我需要这个输出:

我需要使用哪些 SQL 函数、条件子句...?

【问题讨论】:

我在所需的输出中没有看到 XML 标记。 标签是什么?价值观是什么?它是从任何桌子上挑选出来的吗? @Serg ı 只需要一个看起来像 xml 格式的输出。这是关于字母的对齐和必要空格的确定。 @Dawn 不是从任何表中挑选的,我只是输入字符串值。这些都是我找到解决方案的信息。我知道这还不够 很可能是堆栈编程练习。您需要在解析下一个项目时扩展/修剪的开放节点集合。见docs.oracle.com/cd/B28359_01/appdev.111/b28370/… 【参考方案1】:

Oracle 设置

CREATE OR REPLACE TYPE CHARS_TABLE IS TABLE OF CHAR(2);
/
CREATE OR REPLACE TYPE INTEGERS_TABLE IS TABLE OF INTEGER;
/

PL/SQL

这假定了一组格式良好的字符对,并且只是将每对缩进到适当的级别:

DECLARE
  word VARCHAR2(50) := 'a4b4c2d9d9c2e6e6b4s2o1o1s2a4w2r8r8k2g5g5k2w2';
  num  PLS_INTEGER := LENGTH( word ) / 2;
  name_array  CHARS_TABLE    := CHARS_TABLE();
  depth_array INTEGERS_TABLE := INTEGERS_TABLE();
  open_array  INTEGERS_TABLE := INTEGERS_TABLE();
BEGIN
  name_array.EXTEND( num );
  depth_array.EXTEND( num );
  open_array.EXTEND( num );

  name_array(1)  := SUBSTR( word, 1, 2 );
  depth_array(1) := 1;
  open_array(1)  := 1;

  FOR i IN 2 .. num LOOP
    name_array(i) := SUBSTR( word, 2*i - 1, 2 );
    open_array(i) := 1;
    FOR j IN 1 .. i-1 LOOP
      IF name_array(j) = name_array(i) THEN
        open_array(i) := -open_array(i);
      END IF;
    END LOOP;
    depth_array(i) := depth_array(i-1) + open_array(i);
  END LOOP;

  FOR i IN 1 .. num LOOP
    FOR j IN 2 .. depth_array(i) + CASE open_array(i) WHEN 1 THEN 0 ELSE 1 END LOOP
      DBMS_OUTPUT.PUT( '  ' );
    END LOOP;
    DBMS_OUTPUT.PUT_LINE( name_array(i) );
  END LOOP;
END;
/

输出

a4
  b4
    c2
      d9
      d9
    c2
    e6
    e6
  b4
  s2
    o1
    o1
  s2
a4
w2
  r8
  r8
  k2
    g5
    g5
  k2
w2

更新 - 更简单的基于堆栈的版本

DECLARE
  word        CONSTANT VARCHAR2(50) := 'a4b4c2d9d9c2e6e6b4s2o1o1s2a4w2r8r8k2g5g5k2w2';
  num         CONSTANT PLS_INTEGER := LENGTH( word ) / 2;
  name_array  CHARS_TABLE := CHARS_TABLE();
  depth       PLS_INTEGER := 0;
  name        CHAR(2);

  PROCEDURE indent( depth PLS_INTEGER, name CHAR )
  IS
  BEGIN
    FOR j IN 2 .. depth LOOP
      DBMS_OUTPUT.PUT( '  ' );
    END LOOP;
    DBMS_OUTPUT.PUT_LINE( name );
  END;
BEGIN
  name_array.EXTEND( num );

  FOR i IN 1 .. num LOOP
    name := SUBSTR( word, 2*i - 1, 2 );
    IF depth > 0 AND name = name_array(depth) THEN
      indent(depth,name);
      depth := depth - 1;
    ELSE
      depth := depth - 1;
      name_array(depth) := name;
      indent(depth,name);
    END IF;
  END LOOP;
END;
/

【讨论】:

非常感谢 :) 我需要更多帮助。如何反转输出?我的意思是你的输出以 a4 b4 c2 d9.. 开头.. 但我的输出 w2 k3 g5.. .@MT0 @ecenurozturk 看看你的问题和我的回答中的SUBSTR() 电话之间的区别。【参考方案2】:
DECLARE
  vs_CurrentChar VARCHAR2(1);
  vs_NextChar    VARCHAR2(1);
  vs_TempText    VARCHAR2(100);
  vs_InputText   VARCHAR2(100) := 'abcdffdcba';

  vn_LengthOfText NUMBER := 1;
  vn_WhileIndex   NUMBER := 1;

  vs_Spaces VARCHAR(100);
BEGIN
  vs_TempText    := NULL;
  vs_CurrentChar := substr(vs_InputText, vn_WhileIndex, vn_LengthOfText);
  dbms_output.put_line(vs_CurrentChar);

  WHILE vn_WhileIndex < length(vs_InputText) - 1 LOOP

    vs_NextChar := substr(vs_InputText, vn_WhileIndex + 1, vn_LengthOfText);
    EXIT WHEN vs_CurrentChar = vs_NextChar;

    vs_TempText    := vs_TempText || vs_CurrentChar;
    vs_CurrentChar := vs_NextChar;
    vs_Spaces      := NULL;
    FOR i IN 1 .. vn_WhileIndex LOOP
      vs_Spaces := vs_Spaces || chr(9); --'*';
    END LOOP;

    dbms_output.put_line(vs_Spaces || vs_CurrentChar);
    vn_WhileIndex := vn_WhileIndex + 1;
  END LOOP;

  dbms_output.put_line(vs_Spaces || vs_CurrentChar);

  FOR i IN 1 .. length(vs_TempText) LOOP
    vs_Spaces      := substr(vs_Spaces, vn_LengthOfText, length(vs_Spaces) - 1);
    vs_CurrentChar := substr(vs_TempText, -i, vn_LengthOfText);
    dbms_output.put_line(vs_Spaces || vs_CurrentChar);
  END LOOP;
END;
/

并输出:

a
    b
        c
            d
                f
                f
            d
        c
    b
a

甚至,如果你把 '*'; 而不是 chr(9); 那么输出将如下所示:

a
*b
**c
***d
****f
****f
***d
**c
*b
a

【讨论】:

以上是关于如何编写一个 PL/SQL 程序来打印出看起来像 xml 格式的字符串的主要内容,如果未能解决你的问题,请参考以下文章

Oracle PL/SQL 中的漂亮打印

如何打印出非质数? PL/SQL [关闭]

如何使用pl sql中的匿名块打印出整个表?

为啥我在 PL/SQL 中的 for 循环没有打印出最后一次迭代

PL/SQL 打印出存储过程返回的引用游标

带有游标的 pl/sql 可变数组