我有带有多个名称空间的XML,但是所有元素都相同。我需要将此XML转换为JSON,但是我不确定如何动态地传递/更改名称空间,而不用不同的名称空间重复相同的XSLT代码。
因此,我仅在我定义的名称空间的输出中获取数据。
下面是我的示例XML-
<?xml version="1.0" encoding="utf-8"?>
<root>
<wd:Report_Data xmlns:wd="urn:com.workday.report/INT1111a_CR_REV_FINRA_Connect_AR_Adjustment_Transaction">
<wd:Report_Entry>
<wd:company>TESTCOMPANY</wd:company>
<wd:revenue_stream>X</wd:revenue_stream>
<wd:customer_id>XCUSTOMER</wd:customer_id>
<wd:invoice_id>201900000035</wd:invoice_id>
<wd:post_date>2019-05-01</wd:post_date>
<wd:initiatedby>Test Data</wd:initiatedby>
<wd:amount>-100</wd:amount>
<wd:trans_date>2019-04-22</wd:trans_date>
<wd:legacy>false</wd:legacy>
<wd:exported>2019-05-01T12:13:02.773-07:00</wd:exported>
<wd:reason>Credit Invoice</wd:reason>
</wd:Report_Entry>
</wd:Report_Data>
<wd:Report_Data xmlns:wd="urn:com.workday.report/INT1111b_CR_REV_FINRA_Connect_AR_Writeoff_Transaction">
<wd:Report_Entry>
<wd:company>TESTCOMPANY</wd:company>
<wd:revenue_stream>X</wd:revenue_stream>
<wd:customer_id>XCUSTOMER</wd:customer_id>
<wd:invoice_id>201900000020</wd:invoice_id>
<wd:post_date>2019-05-01</wd:post_date>
<wd:amount>30</wd:amount>
<wd:trans_date>2019-04-01</wd:trans_date>
<wd:legacy>false</wd:legacy>
<wd:exported>2019-05-01T12:13:03.030-07:00</wd:exported>
<wd:reason>Disputed Amount</wd:reason>
</wd:Report_Entry>
</wd:Report_Data>
</root>
Below is the XSLT i have created -
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wd="urn:com.workday.report/INT1111a_CR_REV_FINRA_Connect_AR_Adjustment_Transaction" xmlns:wd1="urn:com.workday.report/INT1111b_CR_REV_FINRA_Connect_AR_Writeoff_Transaction" exclude-result-prefixes="xs" version="3.0">
<xsl:mode streamable="yes" on-no-match="shallow-skip"/>
<xsl:output method="text" encoding="UTF-8" indent="no"/>
<xsl:template match="root/wd:Report_Data">
<xsl:iterate select="wd:Report_Entry/copy-of()">
<!--Define Running Totals for Statistics -->
<xsl:param name="TotalCount" select="0"/>
<xsl:param name="TotalAmount" select="0"/>
<!--Write Statistics -->
<xsl:on-completion>
<xsl:text>{"Stats": </xsl:text>
<xsl:text>{"Total Count": </xsl:text>
<xsl:value-of select="$TotalCount"/>
<xsl:text>,</xsl:text>
<xsl:text>"Total Amount": </xsl:text>
<xsl:value-of select="$TotalAmount"/>
<xsl:text>}}</xsl:text>
</xsl:on-completion>
<!--Write Details -->
<xsl:text>{"id": "</xsl:text>
<xsl:value-of select="wd:id"/>
<xsl:text>",</xsl:text>
<xsl:text>"company": "</xsl:text>
<xsl:value-of select="wd:company"/>
<xsl:text>",</xsl:text>
<xsl:text>"trans_type": "</xsl:text>
<xsl:value-of select="wd:trans_type"/>
<xsl:text>",</xsl:text>
<xsl:text>"revenue_stream": "</xsl:text>
<xsl:value-of select="wd:revenue_stream"/>
<xsl:text>",</xsl:text>
<xsl:text>"customer_id": "</xsl:text>
<xsl:value-of select="wd:customer_id"/>
<xsl:text>",</xsl:text>
<xsl:text>"invoice_id": "</xsl:text>
<xsl:value-of select="wd:invoice_id"/>
<xsl:text>",</xsl:text>
<xsl:text>"post_date": "</xsl:text>
<xsl:value-of select="wd:post_date"/>
<xsl:text>",</xsl:text>
<xsl:text>"initiatedby": "</xsl:text>
<xsl:value-of select="wd:initiatedby"/>
<xsl:text>",</xsl:text>
<xsl:text>"amount": </xsl:text>
<xsl:value-of select="wd:amount"/>
<xsl:text>,</xsl:text>
<xsl:text>"trans_date": "</xsl:text>
<xsl:value-of select="wd:trans_date"/>
<xsl:text>",</xsl:text>
<xsl:text>"legacy": </xsl:text>
<xsl:value-of select="wd:legacy"/>
<xsl:text>,</xsl:text>
<xsl:text>"exported": "</xsl:text>
<xsl:value-of select="wd:exported"/>
<xsl:text>"}</xsl:text>
<!--Store Running Totals -->
<xsl:next-iteration>
<xsl:with-param name="TotalCount" select="$TotalCount + 1"/>
<xsl:with-param name="TotalAmount" select="$TotalAmount + wd:amount"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:template>
</xsl:stylesheet>
Expected Result -
{
"id": "",
"company": "TESTCOMPANY",
"trans_type": "",
"revenue_stream": "",
"customer_id": "XCUSTOMER",
"invoice_id": "201900000035",
"post_date": "2019-05-01",
"initiatedby": "Test Data",
"amount": -100,
"trans_date": "2019-04-22",
"legacy": false,
"exported": "2019-05-01T12:13:02.773-07:00"
}
{
"id": "",
"company": "TESTCOMPANY",
"trans_type": "",
"revenue_stream": "X",
"customer_id": "XCUSTOMER",
"invoice_id": "201900000035",
"post_date": "2019-05-01",
"initiatedby": "Test Data",
"amount": -100,
"trans_date": "2019-04-22",
"legacy": false,
"exported": "2019-05-01T12:13:02.773-07:00"
} {
"Stats": {
"Total Count": 2,
"Total Amount": -200
}
}
答案 0 :(得分:0)
这里是一个使用通配符选择器*:foo
和累加器来生成JSON输出的示例,因为我所知道的唯一的XSLT 3流处理器是Saxon 9 EE,我还使用了扩展元素saxon:array
,因为这样可以更轻松地创建带有数组的JSON输出。在仅具有XPath 3.1数组构造函数[]
和array { }
的纯XSLT 3中,从像xsl:apply-templates
这样的XSLT指令中即时生成数组数据总是很麻烦。 >
<?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"
xmlns:saxon="http://saxon.sf.net/"
extension-element-prefixes="saxon"
exclude-result-prefixes="#all" version="3.0">
<xsl:mode use-accumulators="#all" streamable="yes"/>
<xsl:output method="json" indent="yes"/>
<xsl:accumulator name="entry-count" as="xs:integer" initial-value="0" streamable="yes">
<xsl:accumulator-rule match="*:Report_Data/*:Report_Entry" select="$value + 1"/>
</xsl:accumulator>
<xsl:accumulator name="amount-sum" as="xs:decimal" initial-value="0" streamable="yes">
<xsl:accumulator-rule match="*:Report_Data/*:Report_Entry/*:amount/text()"
select="$value + xs:decimal(.)"/>
</xsl:accumulator>
<xsl:template match="root">
<xsl:map>
<xsl:map-entry key="local-name()">
<saxon:array>
<xsl:apply-templates select="*:Report_Data/*:Report_Entry"/>
<xsl:sequence
select="
map {
'Stats': map {
'Total Count': accumulator-after('entry-count'),
'Total Amount': accumulator-after('amount-sum')
}
}"
/>
</saxon:array>
</xsl:map-entry>
</xsl:map>
</xsl:template>
<xsl:template match="*:Report_Entry">
<xsl:sequence
select="
map {
'id': string(*:id),
'amount': xs:decimal(*:amount)
}"
/>
</xsl:template>
</xsl:stylesheet>
不幸的是,在oXygen 21、9.8.0.12和9.9.1.1中提供了两个版本的Saxon 9 EE,这仅通过了9.9中的流动性分析,因此结果是
{
"root": [
{
"amount": -100,
"id": null
},
{
"amount": 30,
"id": null
},
{
"Stats": {
"Total Count": 2,
"Total Amount": -70 } }
] }
当然,使用通配符*:foo
的方法也可以与您的xsl:iterate
方法一起使用:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wd="urn:com.workday.report/INT1111a_CR_REV_FINRA_Connect_AR_Adjustment_Transaction" xmlns:wd1="urn:com.workday.report/INT1111b_CR_REV_FINRA_Connect_AR_Writeoff_Transaction" exclude-result-prefixes="xs" version="3.0">
<xsl:mode streamable="yes" on-no-match="shallow-skip"/>
<xsl:output method="text" encoding="UTF-8" indent="no"/>
<xsl:template match="root">
<xsl:iterate select="*:Report_Data/*:Report_Entry/copy-of()">
<!--Define Running Totals for Statistics -->
<xsl:param name="TotalCount" select="0"/>
<xsl:param name="TotalAmount" select="0"/>
<!--Write Statistics -->
<xsl:on-completion>
<xsl:text>{"Stats": </xsl:text>
<xsl:text>{"Total Count": </xsl:text>
<xsl:value-of select="$TotalCount"/>
<xsl:text>,</xsl:text>
<xsl:text>"Total Amount": </xsl:text>
<xsl:value-of select="$TotalAmount"/>
<xsl:text>}}</xsl:text>
</xsl:on-completion>
<!--Write Details -->
<xsl:text>{"id": "</xsl:text>
<xsl:value-of select="*:id"/>
<xsl:text>",</xsl:text>
<xsl:text>"company": "</xsl:text>
<xsl:value-of select="*:company"/>
<xsl:text>",</xsl:text>
<xsl:text>"trans_type": "</xsl:text>
<xsl:value-of select="*:trans_type"/>
<xsl:text>",</xsl:text>
<xsl:text>"revenue_stream": "</xsl:text>
<xsl:value-of select="*:revenue_stream"/>
<xsl:text>",</xsl:text>
<xsl:text>"customer_id": "</xsl:text>
<xsl:value-of select="*:customer_id"/>
<xsl:text>",</xsl:text>
<xsl:text>"invoice_id": "</xsl:text>
<xsl:value-of select="*:invoice_id"/>
<xsl:text>",</xsl:text>
<xsl:text>"post_date": "</xsl:text>
<xsl:value-of select="*:post_date"/>
<xsl:text>",</xsl:text>
<xsl:text>"initiatedby": "</xsl:text>
<xsl:value-of select="*:initiatedby"/>
<xsl:text>",</xsl:text>
<xsl:text>"amount": </xsl:text>
<xsl:value-of select="*:amount"/>
<xsl:text>,</xsl:text>
<xsl:text>"trans_date": "</xsl:text>
<xsl:value-of select="*:trans_date"/>
<xsl:text>",</xsl:text>
<xsl:text>"legacy": </xsl:text>
<xsl:value-of select="*:legacy"/>
<xsl:text>,</xsl:text>
<xsl:text>"exported": "</xsl:text>
<xsl:value-of select="*:exported"/>
<xsl:text>"}</xsl:text>
<!--Store Running Totals -->
<xsl:next-iteration>
<xsl:with-param name="TotalCount" select="$TotalCount + 1"/>
<xsl:with-param name="TotalAmount" select="$TotalAmount + *:amount"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:template>
</xsl:stylesheet>