【问题标题】:xslt standardize nested JSONxslt 标准化嵌套的 JSON
【发布时间】:2021-12-31 02:35:18
【问题描述】:

我使用通用 XSL 来标准化不同的嵌套 JSON。 我的 JSON 示例

/soccer2.json

{
"position": "main", 
"others": "spiss;sweeper", 
"player": 
  {
    "midtbane": [
      "offensiv-midtbane", 
      "defensiv-midtbane"
    ]
  }
}

/soccer1.json

{
 "position": "main", 
 "others": [
    {
        "wing": "høyreving;venstreving", 
        "fullback": [
              "venstreback", 
              "høyreback"
        ]
    }
  ], 
  "player": [
        {
          "left": "venstre-midtbane", 
          "center": "høyre-midtbane", 
          "right": "sentral-midtbane"
        }
    ]   
  }

我的 xsl

const myXsl =
  fn.head(xdmp.unquote(
`
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">  
  
    <xsl:template match="/">
        <sport>
            <xsl:if test="exists(position)">
                <positionType>
                  <xsl:copy-of select="position"/>
                </positionType>
            </xsl:if> 
            
        <!--    <xsl:if test="exists(others)">
                <otherPosition>
                  <xsl:copy-of select="others"/>
                </otherPosition>
            </xsl:if>   
-->
 
            <xsl:if test="exists(player)">
                <playerPosition>
                   <xsl:for-each select="player/child::node()">
                     <xsl:element name="{name()}">  
                        <xsl:value-of select="."/>
                     </xsl:element>  
                   </xsl:for-each>
                </playerPosition>
            </xsl:if>            
        </sport>
    </xsl:template>
    
</xsl:transform>
`));
const doc = cts.doc('/soccer2.json')
xdmp.xsltEval(myXsl, doc)

意外输出:

/soccer2.json
<sport>
  <positionType>main</positionType>
  <otherPosition>spiss;sweeper</otherPosition>
  <playerPosition>
    <midtbane>["offensiv-midtbane", "defensiv-midtbane"]</midtbane>
  </playerPosition>
</sport>

预期输出:

/soccer2.json
<sport>
  <positionType>main</positionType>
  <otherPosition>spiss;sweeper</otherPosition>
  <playerPosition>
    <midtbane>offensiv-midtbane</midtbane>
    <midtbane>defensiv-midtbane</midtbane>
  </playerPosition>
</sport>

我希望这项工作在 XSLT 中发挥作用吗?

【问题讨论】:

  • 您的描述中缺少某些内容。 XSLT 的输入是 XML,而不是 JSON。 XSLT 3.0 处理器可以读取 JSON - 但您的样式表显示version="2.0" 并且不包含解析JSON 的尝试。显然,在将 JSON 输入 XSL 转换之前,您有一个将 JSON 转换为 XML 的初步阶段。我们需要查看那个 XML。尝试使用仅包含 identity transform template 的样式表来获取它。
  • 不用担心,感谢大家的帮助! (我们会非常详细地阅读每条回复和评论。而且我们不会错过任何事情。)

标签: javascript json xslt nosql marklogic


【解决方案1】:

XSLT 3.0 具有处理 JSON 的能力:早期版本没有。您似乎没有使用 XSLT 3.0 功能来处理 JSON。

(您已将其标记为“marklogic” - 也许 ML XSLT 处理器中的某些东西可以完成这项工作;我不知道)。

我希望您的代码只是说输入不是格式正确的 XML 失败。

【讨论】:

  • 没有。输入都是有效的。而且我看不出 XSLT 3 是如何完成这项工作的。请展示您的解决方案。
  • MarkLogic 可以将 XSLT 转换应用于 JSON 文档。目前存在一些问题,但这是可能的。该功能早于用于 JSON 支持的新 XSLT 3.0 功能。
  • @Mads Hansen:您能否将您的 MarkLogic xsl 展示为尽最大努力?我的问题是将最简单的 JSON 转换为 xml。
  • @Chris 您似乎依赖于我不熟悉的 Marklogic XSLT 处理器的一个特性。抱歉,我没有时间为您提供有效的 XSLT 3.0 解决方案。
【解决方案2】:

MarkLogic XSLT 实现,您应该看看:

const implFlattenJToX=
  fn.head(xdmp.unquote(
`
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xdmp="http://marklogic.com/xdmp"
    xdmp:dialect="1.0-ml" exclude-result-prefixes="xdmp" version="2.0">
        
    <xsl:template name="sport">        
        <xsl:variable name="v_position" select="position"/>
        <xsl:variable name="v_others" select="others"/>
        <xsl:variable name="v_player" select="player"/>        
        <sport>
            <xsl:if test="exists(position)">
                <positionType>
                    <xsl:copy-of select="position"/>
                </positionType>
            </xsl:if> 
            <xsl:choose>
                <xsl:when test="exists($v_others/node())">                     
                    <otherPosition>
                        <xsl:for-each select="$v_others">
                            <xsl:call-template name="flattenJson"/>
                        </xsl:for-each>
                    </otherPosition>  
                </xsl:when>
                <xsl:otherwise>
                    <xsl:if test="exists($v_others)">
                        <xsl:apply-templates select="$v_others" mode="flatNode">
                            <xsl:with-param name="eName" select="'otherPosition'"/>
                        </xsl:apply-templates>   
                    </xsl:if>
                </xsl:otherwise>
            </xsl:choose>             
            <xsl:if test="exists($v_player)">
                <playerPosition>
                    <xsl:for-each select="/player">
                        <xsl:call-template name="flattenJson"/>
                    </xsl:for-each>
                </playerPosition>
            </xsl:if>      
        </sport>
    </xsl:template>
    
    <xsl:template name="flattenJson">
        <xsl:for-each select="*"> 
            <xsl:choose>
                <xsl:when test="array-node()|object-node()">
                    <xsl:for-each select="./node()">
                        <xsl:apply-templates select="xdmp:from-json(.)"/>
                    </xsl:for-each>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:element name="{(name(.))}">
                        <xsl:value-of select="."/>
                    </xsl:element>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each> 
    </xsl:template> 
    
    <xsl:template match="*" mode="flatNode">
        <xsl:param name="eName"/>
        <xsl:element name="{$eName}">
            <xsl:value-of select="."/>
        </xsl:element>
    </xsl:template>     
    
    <xsl:template match="/">
        <xsl:call-template name="sport"/>
    </xsl:template>
    
</xsl:transform>

`));

输出:

<sport>
    <positionType>main</positionType>
    <otherPosition>
        <wing>høyreving;venstreving</wing>
        <fullback>venstreback</fullback>
        <fullback>høyreback</fullback>
    </otherPosition>
    <playerPosition>
        <left>venstre-midtbane</left>
        <center>høyre-midtbane</center>
        <right>sentral-midtbane</right>
    </playerPosition>
</sport>

<sport>
    <positionType>main</positionType>
    <otherPosition>spiss;sweeper</otherPosition>
    <playerPosition>
        <midtbane>offensiv-midtbane</midtbane>
        <midtbane>defensiv-midtbane</midtbane>
    </playerPosition>
</sport>

旁注:1)MarkLogic 内置函数json:transform-from-json,可以在独立的XQuery 中高效实现| SJS API 或插入为 XSLT import-module,是在 XML 和 JSON 之间导航的另一个助手。 2)flatNode可以调用到flattenJson。 在这个链条中,我尽量让 XSL 方言与您的方言接近。

实际上,我只需要稍微调整 XPath 而无需触及基本模板 flattenJsonflatNode 即可协调复杂的 JSON。

【讨论】:

  • &lt;xsl:if test="exists(others)"&gt;&lt;otherPosition&gt;&lt;xsl:for-each select="/others"&gt;&lt;xsl:call-template name="flattenJson"/&gt;&lt;/xsl:for-each&gt;&lt;/otherPosition&gt;&lt;/xsl:if&gt;
  • 谢谢你,菲奥娜!它解决了player 数组问题。当我使用类似的逻辑来转换others 时,它并没有将 JSON 转换为预期的 XML。你能指出哪里出了问题吗? XSLT3 真的会转换 JSON 吗?
  • @Chris:请查看修改后的内容。如果前端加载 XSLT 3,应该没问题。如果后端将 XSLT 3 加载到 MarkLogic 中,我感觉它不会远程同步。
  • 女士。 Fiona:更新后的 Xsl 将 JSON 转换为预期的结果!!
  • 在原始 XSLT 中,对 XPath 进行简单调整以选择作为 player 后代的 text() 节点将处理 array-node() 中的单个值或多个值:&lt;xsl:for-each select="player//text()"&gt;
猜你喜欢
  • 2021-09-30
  • 2016-05-14
  • 1970-01-01
  • 2015-12-15
  • 2021-01-13
  • 2016-12-13
  • 1970-01-01
  • 2013-06-17
  • 1970-01-01
相关资源
最近更新 更多