【发布时间】:2019-07-02 22:23:57
【问题描述】:
我正在尝试生成一个 XSLT 以将 XML 文件转换为 JSON 格式,包括在 Solr 中正确索引的所有必要字段。
我当前的 XSLT 文件如下:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">{
<xsl:apply-templates select="*"/>}
</xsl:template>
<!-- Object or Element Property-->
<xsl:template match="*">
<xsl:variable name="childDoc" select="name(*[1])"/>
<xsl:choose>
<xsl:when test="count(*[name()=$childDoc]) >= 1">
"Document":"<xsl:value-of select="name()"/>", <xsl:call-template name="Properties"/>
</xsl:when>
<xsl:otherwise>
"<xsl:value-of select="name()"/>": <xsl:call-template name="Properties"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Array Parent Node -->
<xsl:template match="*" mode="ArrayParentNode">
<xsl:call-template name="Path"/>
</xsl:template>
<!-- Array Element -->
<xsl:template match="*" mode="ArrayElement">
<xsl:call-template name="Properties"/>
</xsl:template>
<!-- Object Properties -->
<xsl:template name="Properties">
<xsl:variable name="childName" select="name(*[1])"/>
<xsl:choose>
<xsl:when test="not(*|@*)">"<xsl:value-of select="."/>"</xsl:when>
<xsl:when test="count(*[name()=$childName]) > 1">
"_childDocuments_":[
{ "<xsl:value-of select="$childName"/>" :[<xsl:apply-templates select="*" mode="ArrayElement"/>]
}
]
</xsl:when>
<xsl:otherwise>
"_childDocuments_":[
{
<xsl:apply-templates select="." mode="ArrayParentNode"/>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*"/>
}
]
</xsl:otherwise>
</xsl:choose>
<xsl:if test="following-sibling::*">,</xsl:if>
</xsl:template>
<!-- Attribute Property -->
<xsl:template match="@*">"<xsl:value-of select="name()"/>" : "<xsl:value-of select="."/>",</xsl:template>
<!--Path-->
<xsl:template name = "Path">
<xsl:variable name="ances" select="ancestor-or-self::node()"/>
<xsl:variable name="ancestros">
<xsl:for-each select="$ances">
<xsl:value-of select="concat(name(),'.')"/>
</xsl:for-each>
</xsl:variable>
"Path": "<xsl:value-of select = "substring($ancestros,2,string-length($ancestros)-2)"/>",
</xsl:template>
</xsl:stylesheet>
举个例子:
<Reporte>
<id>10</id>
<Operacion>
<id>10.1</id>
<Tipo_Operacion>Ejemplo</Tipo_Operacion>
<Fecha>10/10/2010</Fecha>
<Monto>12345</Monto>
</Operacion>
<bla>123456ytgfde</bla>
<Persona_Fisica>
<id>10.2</id>
<Nombre>Juan</Nombre>
<Apellido>Perez</Apellido>
<Domicilio>
<id>10.2.1</id>
<Calle>Yrigoyen</Calle>
<Numero>123</Numero>
</Domicilio>
<Telefono>
<id>10.2.2</id>
<Prefijo>11</Prefijo>
<Numero>12345678</Numero>
</Telefono>
</Persona_Fisica>
<Persona_Fisica>
<id>10.3</id>
<Nombre>Roberto Carlos</Nombre>
<Apellido>De Souza</Apellido>
<PEP>true</PEP>
<Domicilio>
<id>10.3.1</id>
<Calle>Falsa</Calle>
<Numero>678</Numero>
</Domicilio>
<Telefono>
<id>10.3.2</id>
<Prefijo>11</Prefijo>
<Numero>87654321</Numero>
</Telefono>
</Persona_Fisica>
<Persona_Juridica>
<id>10.4</id>
<Denominacion>Lavado SRL</Denominacion>
<CUIT>23-32480636-9</CUIT>
</Persona_Juridica>
</Reporte>
我的输出如下:
{
"Document":"Reporte",
"_childDocuments_":[
{
"Path": "Reporte",
"id": "11",
"Document":"Operacion",
"_childDocuments_":[
{
"Path": "Reporte.Operacion",
"id": "10.1",
"Tipo_Operacion": "Ejemplo",
"Fecha": "10/10/2010",
"Monto": "12345"
}
]
,
"bla": "123456ytgfde",
"Document":"Persona_Fisica",
"_childDocuments_":[
{
"Path": "Reporte.Persona_Fisica",
"id": "10.2",
"Nombre": "Juan",
"Apellido": "Perez",
"Document":"Domicilio",
"_childDocuments_":[
{
"Path": "Reporte.Persona_Fisica.Domicilio",
"id": "10.2.1",
"Calle": "Yrigoyen",
"Numero": "123"
}
]
,
"Document":"Telefono",
"_childDocuments_":[
{
"Path": "Reporte.Persona_Fisica.Telefono",
"id": "10.2.2",
"Prefijo": "11",
"Numero": "12345678"
}
]
}
]
,
"Document":"Persona_Fisica",
"_childDocuments_":[
{
"Path": "Reporte.Persona_Fisica",
"id": "10.3",
"Nombre": "Roberto Carlos",
"Apellido": "De Souza",
"PEP": "true",
"Document":"Domicilio",
"_childDocuments_":[
{
"Path": "Reporte.Persona_Fisica.Domicilio",
"id": "10.3.1",
"Calle": "Falsa",
"Numero": "678"
}
]
,
"Document":"Telefono",
"_childDocuments_":[
{
"Path": "Reporte.Persona_Fisica.Telefono",
"id": "10.3.2",
"Prefijo": "11",
"Numero": "87654321"
}
]
}
]
,
"Document":"Persona_Juridica",
"_childDocuments_":[
{
"Path": "Reporte.Persona_Juridica",
"id": "10.4",
"Denominacion": "Lavado SRL",
"CUIT": "23-32480636-9"
}
]
}
]
}
不考虑缩进(因为它是可取的但不是必需的),我期望如下所示:
{
"Document": "Reporte",
"Path": "Reporte",
"id": "12",
"bla": "123456ytgfde",
"_childDocuments_": [
{
"Document": "Operacion",
"Path": "Reporte.Operacion",
"id": "10.1",
"Tipo_Operacion": "Ejemplo",
"Fecha": "10/10/2010",
"Monto": "12345"
},
{
"Document": "Persona_Fisica",
"Path": "Reporte.Persona_Fisica",
"id": "10.2",
"Nombre": "Juan",
"Apellido": "Perez",
"_childDocuments_": [
{
"Document": "Domicilio",
"Path": "Reporte.Persona_Fisica.Domicilio",
"id": "10.2.1",
"Calle": "Yrigoyen",
"Numero": "123"
},
{
"Document": "Telefono",
"Path": "Reporte.Persona_Fisica.Telefono",
"id": "10.2.2",
"Prefijo": "11",
"Numero": "12345678"
}
]
},
{
"Document": "Persona_Fisica",
"Path": "Reporte.Persona_Fisica",
"id": "10.3",
"Nombre": "Roberto Carlos",
"Apellido": "De Souza",
"PEP": "true",
"_childDocuments_": [
{
"Document": "Domicilio",
"Path": "Reporte.Persona_Fisica.Domicilio",
"id": "10.3.1",
"Calle": "Falsa",
"Numero": "678"
},
{
"Document": "Telefono",
"Path": "Reporte.Persona_Fisica.Telefono",
"id": "10.3.2",
"Prefijo": "11",
"Numero": "87654321"
}
]
},
{
"Document": "Persona_Juridica",
"Path": "Reporte.Persona_Juridica",
"id": "10.4",
"Denominacion": "Lavado SRL",
"CUIT": "23-32480636-9"
}
]
}
总结一下,我的 XSLT 还缺少什么:
- “Reporte”中没有任何子元素的元素(如 “文档”:“报告”,“路径”:“报告”,“id”:“10”,“bla”: "123456ytgfde") 应该在第一个 childDocuments 之外 元素。
- 只有一个 childDocuments 元素具有多个 应创建子文档,而不是每个子文档一个。
- “文档”元素应该在相应的之后 childDocuments 而不是之前(与“路径”元素并排,这没关系)。
- 漂亮的缩进(恰到好处)。
【问题讨论】:
-
您是否仅限于 XSLT 1? JSON 中的属性顺序是否重要? XSLT 3(自 2017 年起可用)内置 JSON 支持和序列化,因此您可以轻松地在其中编写模板,创建 XSLT 3/XPath 3.1 映射和数组并将它们序列化为
json,例如,请参阅 xsltfiddle.liberty-development.net/94rmq5S。 -
我在 Nifi 中使用了 TransformXML 处理器,但我找不到它无法运行的 XSLT 版本。但是,我尝试运行您附加的转换并以错误结束,所以我猜它不支持 XSLT 3。
-
如果可能的话,最好用 XSLT 1 来解决。
-
“我在 Nifi 中使用了 TransformXML 处理器,但我找不到它在任何地方运行的 XSLT 版本”:任何 XSLT 处理器都允许您运行输出例如
<xsl:value-of select="system-property('xsl:version')"/>找出答案。 -
gitbox.apache.org/repos/… 似乎暗示他们包括 Saxon HE,至少看起来是 9.6,所以你应该支持 XSLT 2。如果您将 Saxon 9.9 或 9.8 HE 从 Maven 或 Sourceforge 放到 Nifi 类路径中,则可能更容易使用 XSLT 3。