我有一个深度嵌套的xml文件,并希望将其转换为flat csv。因此,我必须走最深的路径(此处:availability
),并重复使用来自父母的值(此处:category
,element
)。
示例:
<market>
<category>
<type>kids</type>
</category>
<items>
<element>
<name>police car</name>
<type>toy</type>
<color>blue</color>
<availability>
<stock cat="A" in="5"/>
<stock cat="B" in="2"/>
</availability>
</element>
</element>
...
</element>
</items>
</market>
所需的csv输出:
kids,police car, toy, blue, A, 5
kids,police car, toy, blue, B, 2
请注意kids
值如何复制到每个生成的element
行,以及每个element
如何复制到每个availability
视图。
我盯着如下,但当然这并没有给出理想的结果。因为我不知道如何:
正确迭代嵌套的子元素
将值连接为csv,重新生成父项找到的值
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" omit-xml-declaration="yes" indent="no"/> <xsl:template match="market"> <xsl:for-each select="//category"> <xsl:value-of select="type"/> </xsl:for-each> <xsl:for-each select="//items//element"> <xsl:value-of select="name"/> <xsl:value-of select="type"/> <xsl:value-of select="color"/> </xsl:for-each> <xsl:for-each select="//items//element//availability//stock"> <xsl:value-of select="//@cat"/> <xsl:value-of select="//@in"/> </xsl:for-each> </xsl:template>
以下可能有效,但我不知道这是否可行:
<xsl:template match="market">
<xsl:variable name="ctype">
<xsl:value-of select="market/category/type"/>
</xsl:variable>
<xsl:for-each select="//items//element">
<xsl:variable name="elem">
<xsl:text>;</xsl:text>
<xsl:value-of select="copy-of(.)!(.//name, .//type, .//color)" separator=";"/>
</xsl:variable>
<!-- nesting for-each -->
<xsl:for-each select="availability//stock">
<xsl:copy-of select="$elem"/>
<xsl:text>;</xsl:text>
<xsl:value-of select="copy-of(.)!(.//@cat, .//@in)" separator=";"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
答案 0 :(得分:1)
我通常会编写一个匹配那些映射到一行的元素的模板,并根据需要通过XPath导航选择其他值:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:apply-templates select="//availability/stock"/>
</xsl:template>
<xsl:template match="stock">
<xsl:value-of select="ancestor::market/category/type, ancestor::element!(name, type, color), @cat, @in" separator=", "/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
这允许使用紧凑且清晰的符号表示哪些值构成CSV文件中的一行。
https://xsltfiddle.liberty-development.net/jyH9rM9
像category/type
这样的静态标头信息也可以存储在全局变量中:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:output method="text"/>
<xsl:variable name="category-type" select="market/category/type"/>
<xsl:template match="/">
<xsl:apply-templates select="//availability/stock"/>
</xsl:template>
<xsl:template match="stock">
<xsl:value-of select="$category-type, ancestor::element!(name, type, color), @cat, @in" separator=", "/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/jyH9rM9/1
XSLT 3中的第三种方法是使用累加器以声明方式捕获值:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="3.0">
<xsl:mode use-accumulators="#all"/>
<xsl:output method="text"/>
<xsl:accumulator name="cat-type" as="xs:string?" initial-value="()">
<xsl:accumulator-rule match="market/category/type" select="string()"/>
</xsl:accumulator>
<xsl:accumulator name="element-name" as="xs:string?" initial-value="()">
<xsl:accumulator-rule match="item/element" select="()"/>
<xsl:accumulator-rule match="items/element/name" select="string()"/>
</xsl:accumulator>
<xsl:accumulator name="element-type" as="xs:string?" initial-value="()">
<xsl:accumulator-rule match="item/element" select="()"/>
<xsl:accumulator-rule match="items/element/type" select="string()"/>
</xsl:accumulator>
<xsl:accumulator name="element-color" as="xs:string?" initial-value="()">
<xsl:accumulator-rule match="item/element" select="()"/>
<xsl:accumulator-rule match="items/element/color" select="string()"/>
</xsl:accumulator>
<xsl:template match="/">
<xsl:apply-templates select="//availability/stock"/>
</xsl:template>
<xsl:template match="stock">
<xsl:value-of select="accumulator-before('cat-type'), accumulator-before('element-name'), accumulator-before('element-type'), accumulator-before('element-color'), @cat, @in" separator=", "/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/jyH9rM9/2
这样做的好处是,您可以通过一些更改使其适应流式传输,您可以使用Saxon 9.8 EE转换大量输入,而无需将完整的XML输入树存储在内存中:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="3.0">
<xsl:mode use-accumulators="#all" />
<xsl:output method="text"/>
<xsl:accumulator name="cat-type" as="xs:string?" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="market/category/type/text()" select="string()"/>
</xsl:accumulator>
<xsl:accumulator name="element-name" as="xs:string?" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="item/element" select="()"/>
<xsl:accumulator-rule match="items/element/name/text()" select="string()"/>
</xsl:accumulator>
<xsl:accumulator name="element-type" as="xs:string?" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="item/element" select="()"/>
<xsl:accumulator-rule match="items/element/type/text()" select="string()"/>
</xsl:accumulator>
<xsl:accumulator name="element-color" as="xs:string?" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="item/element" select="()"/>
<xsl:accumulator-rule match="items/element/color/text()" select="string()"/>
</xsl:accumulator>
<xsl:template match="/">
<xsl:apply-templates select="outermost(//availability/stock)"/>
</xsl:template>
<xsl:template match="stock">
<xsl:value-of select="accumulator-before('cat-type'), accumulator-before('element-name'), accumulator-before('element-type'), accumulator-before('element-color'), @cat, @in" separator=", "/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:0)
试试这个:
kids, police car, toy, blue, A, 5
kids, police car, toy, blue, B, 2
<强>输出强>
{
"/api/*": {
"target": "http://localhost:8090",
"secure": false,
"logLevel": "debug"
}
}