如何使用XQuery将非结构化xml转换为结构化xml

时间:2013-12-30 19:36:12

标签: xml xquery transformation

如何将非结构化xml转换为结构化&使用Xquery所需的表格,欣赏快速帮助

以Section为根节点输入XML文件。

<Section>
<LowerAlpha>a</LowerAlpha>
<Number>1</Number>
<LowerAlpha>b</LowerAlpha>
<Number>1</Number>
<Roman>i</Roman>
<UpperAlpha>A</UpperAlpha>
<UpperAlpha>B</UpperAlpha>
<UpperAlpha>C</UpperAlpha>
<Roman>ii</Roman>
<Roman>iii</Roman>
<Number>2</Number>
<Number>3</Number>
<LowerAlpha>c</LowerAlpha>
<Number>1</Number>
<Number>2</Number>
<Roman>i</Roman>
</Section>

输出xml文件(Section - &gt; LowerAlpha - &gt; Number - &gt; Roman - &gt; UpperAlpha和包含在value标签中的数据。)

<Section>
<LowerAlpha>
<value>a</value>
<Number><value>1</value></Number>
</LowerAlpha>
<LowerAlpha>
<value>b</value>
<Number>
<value>1</value>
<Roman>
<value>i</value>
<UpperAlpha><value>A</value></UpperAlpha>
<UpperAlpha><value>B</value></UpperAlpha>
<UpperAlpha><value>C</value></UpperAlpha>
</Roman>
<Roman><value>ii</value></Roman>
<Roman><value>iii</value></Roman>
</Number>
<Number>2</Number>
<Number>3</Number>
</LowerAlpha>
<LowerAlpha><value>c</value>
<Number><value>1</value></Number>
<Number><value>2</value>
<Roman><value>i</value></Roman>
</Number>
</LowerAlpha>
</Section>

1 个答案:

答案 0 :(得分:1)

使用递归。该解决方案与XSLT有一些相似之处,但增加了逻辑以遵循特定于应用程序的嵌套规则。但是,它应该足够通用以适应其他嵌套规则:

declare function local:passthru(
    $e as element(),
    $restrict as xs:QName*
) {
    element { node-name($e) } {
        for $n in $e/*[if (exists($restrict)) then 
          node-name(.) = $restrict else true()]
        return local:process($n)
    }
};

declare function local:value-wrap(
    $e as element()
) {
    element { node-name($e) } {
        element value {
            $e/node()
        }
    }
};

declare function local:nest(
  $e as element(),
  $restrict as xs:QName*
)
{
  element { node-name($e) } {
    element value { $e/string() },
    let $next := ($e/following-sibling::*[node-name(.) eq node-name($e)])[1]
    let $children := document{ $e/following-sibling::*[ 
      if (empty($next)) then true() else . << $next] }/*
    for $c in $children[if (exists($restrict)) then 
      node-name(.) = $restrict else true()]
    return local:process($c)
  }
};

declare function local:process( 
    $e as item() 
) as item()?
{
    typeswitch ($e) 
        case element(Section) return local:passthru($e, xs:QName('LowerAlpha'))
        case element(Number) return local:nest($e, (xs:QName('Roman'))) 
        case element(LowerAlpha) return local:nest($e, xs:QName('Number'))
        case element(Roman) return local:nest($e, xs:QName('UpperAlpha'))
        case element(UpperAlpha) return local:value-wrap($e)
        default return ()
};

local:process(**Input XML**)

输出:

<Section>
    <LowerAlpha>
        <value>a</value>
        <Number>
            <value>1</value>
        </Number>
    </LowerAlpha>
    <LowerAlpha>
        <value>b</value>
        <Number>
            <value>1</value>
            <Roman>
                <value>i</value>
                <UpperAlpha>
                    <value>A</value>
                </UpperAlpha>
                <UpperAlpha>
                    <value>B</value>
                </UpperAlpha>
                <UpperAlpha>
                    <value>C</value>
                </UpperAlpha>
            </Roman>
            <Roman>
                <value>ii</value>
            </Roman>
            <Roman>
                <value>iii</value>
            </Roman>
        </Number>
        <Number>
            <value>2</value>
        </Number>
        <Number>
            <value>3</value>
        </Number>
    </LowerAlpha>
    <LowerAlpha>
        <value>c</value>
        <Number>
            <value>1</value>
        </Number>
        <Number>
            <value>2</value>
            <Roman>
                <value>i</value>
            </Roman>
        </Number>
    </LowerAlpha>
</Section>