带XmlExtractor的U-SQL - 元素

时间:2017-09-14 09:08:46

标签: azure-data-lake u-sql

在U-SQL中,我试图使用XmlExtractor获取元素内的元素列表。但是我无法获得嵌套的集合。

这是一个包含位置的项目列表。使用XmlExtractor我可以获得一系列元素,但我不知道如何获得包含集合的集合。 XML示例如下所示。

有什么想法吗?

<root>
<Item>
    <Header>
        <id>111</id>
    </Header>
    <Body>
        <Locations>
            <Location>
                <Station>k4</Station>
                <Timestamp>2017-08-30T02:04:18.2506945+02:00</Timestamp>
            </Location>
            <Location>
                <Station>k5</Station>
                <Timestamp>2017-08-30T02:04:18.2506945+02:00</Timestamp>
            </Location>
        </Locations>
    </Body>
</Item>
<Item>
    <Header>
        <id>222</id>
    </Header>
    <Body>
        <Locations>
            <Location>
                <Station>k4</Station>
                <Timestamp>2017-08-30T02:12:36.1218601+02:00</Timestamp>
            </Location>
            <Location>
                <Station>k5</Station>
                <Timestamp>2017-08-30T02:12:36.1218601+02:00</Timestamp>
            </Location>
        </Locations>
    </Body>
</Item>
</root>

3 个答案:

答案 0 :(得分:1)

解决方法是创建一个在一个字符串中使用XML的提取器,然后使用xpath调用一个方法,返回一个SQL.Array,其中该字符串具有逗号分隔的结果值。结果如下:

111;k4,2017-08-30T02:04:18.2506945+02:00
111;k5,2017-08-30T02:04:18.2506945+02:00
222;k4,2017-08-30T02:12:36.1218601+02:00
222;k5,2017-08-30T02:12:36.1218601+02:00

标准的XmlExtractor无法做到这一点,我还决定最好将xml的解析推迟到解压缩之后,因为同一个xml上可以有多个步骤。

答案 1 :(得分:1)

Azure SQL数据库具有强大的功能来粉碎XML。也许如果这已经在您的房地产/架构中,它可能是一个简单的替代自定义代码?一个简单的例子:

DECLARE @xml XML = '<root>
<Item>
    <Header>
        <id>111</id>
    </Header>
    <Body>
        <Locations>
            <Location>
                <Station>k4</Station>
                <Timestamp>2017-08-30T02:04:18.2506945+02:00</Timestamp>
            </Location>
            <Location>
                <Station>k5</Station>
                <Timestamp>2017-08-30T02:04:18.2506945+02:00</Timestamp>
            </Location>
        </Locations>
    </Body>
</Item>
<Item>
    <Header>
        <id>222</id>
    </Header>
    <Body>
        <Locations>
            <Location>
                <Station>k4</Station>
                <Timestamp>2017-08-30T02:12:36.1218601+02:00</Timestamp>
            </Location>
            <Location>
                <Station>k5</Station>
                <Timestamp>2017-08-30T02:12:36.1218601+02:00</Timestamp>
            </Location>
        </Locations>
    </Body>
</Item>
</root>'


/*
111;k4,2017-08-30T02:04:18.2506945+02:00
111;k5,2017-08-30T02:04:18.2506945+02:00
222;k4,2017-08-30T02:12:36.1218601+02:00
222;k5,2017-08-30T02:12:36.1218601+02:00
*/

SELECT 
    r.c.value('(Header/id/text())[1]', 'int' ) id,
    b.c.value('(Station/text())[1]', 'varchar(10)' ) station,
    b.c.value('(Timestamp/text())[1]', 'varchar(40)' ) [timestamp],
    b.c.value('(Timestamp/text())[1]', 'datetimeoffset' ) [timestamp2]
FROM @xml.nodes('root/Item') r(c)
    CROSS APPLY r.c.nodes('Body/Locations/Location') b(c)

如果XML也存储在表中,您可以执行类似的操作。

我的结果: My results

答案 2 :(得分:0)

这是一个脚本,使用提供的提取器可达到所需的结果。

USE master;

REFERENCE SYSTEM ASSEMBLY [System.Xml]
REFERENCE ASSEMBLY master.[Microsoft.Analytics.Samples.Formats.Xml]

@e = EXTRACT a string, b string
     FROM "CollectTest.xml"
     USING new Microsoft.Analytics.Samples.Formats.Xml.XmlDomExtractor(rowPath:"Item",
                             columnPaths:new SQL.MAP<string, string> { {"Header", "a"}, {"Body", "b"} });
@f = SELECT @e.a, t.c, t.d
     FROM @e
         CROSS APPLY new Microsoft.Analytics.Samples.Formats.Xml.XmlApplier("b","Location", new SQL.MAP<string,string> { {"Station", "c"}, {"Timestamp", "d"} })  AS t(c string, d string);


OUTPUT @f TO "foo.txt" USING  Outputters.Tsv(outputHeader:true);
OUTPUT @e TO "foo2.txt" USING  Outputters.Tsv(outputHeader:true);

第一个行集@e使用XmlDomExtractor在行a中创建一个包含“ ID”和在行b中包含子XML代码的行集。

然后,第二个行集@f使用XmlApplier从嵌套的xml代码中提取值,并将其交叉应用于正确的行。从上面的帖子中复制了示例xml,并将其保存为UColladataRoot文件夹中的“ CollectTest.xml”。

  • 注意:变得懒惰了,Header的输出包含一些不需要的节点语法,但是在@e和@f之间添加一个中间的xpath或XmlApplier步骤应该可以解决这个问题。