javascript - 在 JSON 数组中搜索特定值,然后合并为 XML
问题描述
我只是在不同的数据库中开始这个搜索 JSON 并转换:
/doc1.json:
{
"seller": "s1",
"product": [
"football",
"basketball"
],
"sales": [
{
"football": 60,
"basketball": [
{
"c1": 76,
"c2": 90
}
]
}
]
}
/doc2.json
{
"seller": "s2",
"product": ["football"],
"sales": [
{"football": 80}
]
}
我发现该产品仅包含一个特定项目(如果使用 JavaScript,我会更好),与销售合并,并将结果转换为 XML(使用 XSLT ?)。但我并没有走得很远。首先,我尝试 MarkLogic JS:
cts.search(cts.jsonPropertyValueQuery('product', 'football'))
和许多其他方法,它总是返回 2 个文档。我需要使用模块函数而不是硬编码的 JSON 值。
提前感谢您的帮助。
var doc = cts.doc("/doc1.json");
var foo = fn.head(xdmp.unquote(
`
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"\n\
version="2.0">\n\
<xsl:template match="/">\n\
<root>\n\
<xsl:element name="products">\n\
<xsl:for-each select="product">\n\
<xsl:element name="product">\n\
<xsl:variable name="value" select="."/>\n\
<xsl:value-of select="."/>\n\
<xsl:element name="sales">\n\
<xsl:for-each select="/sales/*[name() = $value]">\n\
<xsl:copy select="."/>\n\
</xsl:for-each>\n\
</xsl:element>\n\
</xsl:element>\n\
</xsl:for-each>\n\
</xsl:element>\n\
</root>\n\
</xsl:template>\n\
<xsl:template match="@*|node()">\n\
<xsl:copy>\n\
<xsl:apply-templates select="@*|node()"/>\n\
</xsl:copy>\n\
</xsl:template>\n\
</xsl:transform>\n\
`));
xdmp.xsltEval(foo, doc);
/doc2.json 应该是:
<root>
<products>
<product>football<sales>80</sales>
</product>
</products>
</root>
/doc1.json 应该是:
<root>
<products>
<product>football<sales>60</sales></product>
<product>basketball<sales>
<c1>76</c1>
<c2>90</c2>
</sales></product>
</products>
</root>
解决方案
SJS:
function valueGetDocUri (collection, propertyPath, propertyValue) {
const result =[];
cts.uris("", null, cts.collectionQuery(collection)).toArray().forEach(uri => {
(cts.values(cts.pathReference(propertyPath), null, null, cts.documentQuery(uri)) == propertyValue) ? result.push(uri) : {}
});
return result;
};
执行(这里我有路径索引/indicator
):
const try3 = ['profile', '/indicator', 'SMA'];
valueGetDocUri(...try3)
在 MarkLogic 中,每个 JSON 数组值都是其关联属性的值。 cts.values
+cts.pathReference
将搜索仅包含指定值词典的路径,在本例中为“SMA”。
样本文件:
- /profile/multi-indicator.json
{
"symbol": "USDEUR",
"date": "2021-08-17",
"indicator": [
"BBANDS",
"SMA",
"MACD"
] ,
"riskAdjusted": [
{ "indicator": [
{
"Treynor": 7.19,
"Jensen": 5.13
}
]
}
],
"technicalAnalysis": [
{
"SMA": 0.8426,
"MACD": [
{
"MACD_Signal": -0.0007,
"MACD_Hist": 0.0026,
"MACD": 0.0020
}
],
"BBANDS": [
{
"realLowerBand": 0.8379,
"realUpperBand": 0.8593,
"realMiddleBand": 0.8486
}
]
}
]
}
解决第二个问题(在你的情况下,
params
用你的替换对象:match = 'product'; merge = 'sales'...等)
let doc = cts.doc("/profile/multi-indicator.json");
var params = {};
params.match = 'indicator';
params.merge = 'technicalAnalysis';
const implJtoX = fn.head(xdmp.unquote(
`
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="schema://fc.fasset/profile"
exclude-result-prefixes="xs"
version="2.0">
<xsl:param name="match"/>
<xsl:param name="merge"/>
<xsl:template match="/">
<profile>
<xsl:apply-templates/>
<xsl:element name="algorithm">
<xsl:for-each select="*[name() eq $match]">
<xsl:element name="indicator">
<xsl:variable name="eName" select="normalize-space(data(.))"/>
<xsl:value-of select="$eName"/>
<xsl:element name="technical">
<xsl:for-each
select="/*[name() eq $merge]/*[name() eq $eName]">
<xsl:choose>
<xsl:when test="*">
<xsl:for-each select="./node()">
<xsl:element name="{normalize-space(name(.))}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:element>
</profile>
</xsl:template>
<xsl:template match="node()">
<xsl:apply-templates/>
</xsl:template>
</xsl:transform>
`));
const JtoX = xdmp.xsltEval(implJtoX, doc, params);
JtoX
从工程的角度来看,您调用JavaScript 函数和 XSL,在搜索结果中传入迭代文档和转换参数。我让你打包 SJS 和 XSL 模块。如果你完成了这个准备,我不明白为什么你不应该尝试多名称空间 XSL 转换(有 xdmp:dialect="1.0-ml"
[MarkLogic 上的责任] 或没有[XSLT 编辑器上的责任])。转换后的模型如下:
<prof:profile xmlns:prof="schema://fc.fasset/profile" xmlns:meta="schema://fc.fasset/svm/meta">
<meta:header>
<meta:IDV1>/svm/d91810d-158-494-ad3-e5afc35a5.xml</meta:IDV1>
<meta:symbol>USDEUR</meta:symbol>
<meta:dateSeries>2021-08-17</meta:dateSeries>
<meta:performance>
<meta:Treynor>7.19</meta:Treynor>
<meta:Jensen>5.13</meta:Jensen>
</meta:performance>
</meta:header>
<prof:algorithm>
<prof:indicator>BBANDS<prof:technical>
<prof:realLowerBand>0.8379</prof:realLowerBand>
<prof:realUpperBand>0.8593</prof:realUpperBand>
<prof:realMiddleBand>0.8486</prof:realMiddleBand>
</prof:technical></prof:indicator>
<prof:indicator>SMA<prof:technical>0.8426</prof:technical></prof:indicator>
<prof:indicator>MACD<prof:technical>
<prof:MACD_Signal>-0.0007</prof:MACD_Signal>
<prof:MACD_Hist>0.0026</prof:MACD_Hist>
<prof:MACD>0.002</prof:MACD>
</prof:technical></prof:indicator>
</prof:algorithm>
</prof:profile>
当然,JavaScript 模块也有它的 XQuery 等价物。它们可以互换地评估彼此或 XSL 模块。尽管 SJS 和 XQY 调用之间存在细微差别,但 XSLT 非常适合此类 XML 转换任务。
推荐阅读
- angularjs - Angularjs日期管道过滤器给出错误的输出
- tensorflow - 将张量流模型转换为精简版的问题
- php - 如果其中一个表包含 mysql 中的单词或字符串,如何不显示任何内容?
- python - 如何在关闭时停止具有无限循环的 Python 守护程序线程?
- javascript - Javascript:遍历数组并修改数组内的项目
- javascript - 通过 const 从一个组件到另一个组件的数据?
- javascript - 在 AngularJS 1.4 中使用服务器端 JSON 数组对象作为登录详细信息
- azure-devops - 如何配置 Azure DevOps 发布管道以打包 PowerShell 脚本?
- cmake - 为什么这个 find_package 在较新的 CMake 版本中失败?
- angular - ng-if判断多个数