U-SQL with XmlExtractor - 元素内的元素
U-SQL with XmlExtractor - elements inside elements
在 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>
通过制作一个提取器来解决,该提取器在一个字符串中获取 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 的解析推迟到提取之后,因为同一个 [=17] 可以有多个步骤=].
Azure SQL 数据库具有强大的粉碎能力 XML。也许如果这已经在您的 estate/architecture 中,它可能会成为自定义代码的简单替代方案?一个简单的例子:
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 也存储在 table 中,您可以做类似的事情。
我的结果:
这是一个使用提供的提取器实现预期结果的脚本。
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 是从上面的 post 中复制并保存在 USQLDataRoot 文件夹中的 "CollectTest.xml."
- 注意:懒惰并且 Header 的输出包含一些不需要的节点语法,但在 @e 和 @f 之间添加一个中间 xpath 或 XmlApplier 步骤应该可以解决这个问题。
在 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>
通过制作一个提取器来解决,该提取器在一个字符串中获取 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 的解析推迟到提取之后,因为同一个 [=17] 可以有多个步骤=].
Azure SQL 数据库具有强大的粉碎能力 XML。也许如果这已经在您的 estate/architecture 中,它可能会成为自定义代码的简单替代方案?一个简单的例子:
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 也存储在 table 中,您可以做类似的事情。
我的结果:
这是一个使用提供的提取器实现预期结果的脚本。
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 是从上面的 post 中复制并保存在 USQLDataRoot 文件夹中的 "CollectTest.xml."
- 注意:懒惰并且 Header 的输出包含一些不需要的节点语法,但在 @e 和 @f 之间添加一个中间 xpath 或 XmlApplier 步骤应该可以解决这个问题。