xslt和循环中的变量

时间:2019-05-24 10:33:21

标签: java json xml xslt

我有以下xml

<Request>
   <Record>
      <ID>123456789</ID>
      <OtherID>ABC123</OtherID>
      <Title>Example</Title>
      <Properties>
         <Attribute type="Main">
            <Name>Description</Name>
            <Value>This is an example</Value>
         </Attribute>
         <Attribute type="Main">
            <Name>Source</Name>
            <Value>A1</Value>
         </Attribute>
         <Attribute type="Main">
            <Name>Source</Name>
            <Value>B</Value>
         </Attribute>
         <Attribute type="Main">
            <Name>Represenative</Name>
            <Value>Mike</Value>
         </Attribute>
         <Attribute type="Main">
            <Name>Animal</Name>
            <Value>Elephant</Value>
         </Attribute>
      </Properties>
   </Record>
</Request>

我想要以下json。

{
   "Record":{
      "ID":"123456789",
      "OtherID":"ABC123",
      "Title":"Example",
      "Properties":[
         {
            "Type":"Main",
            "Value":"Source",
            "Name":"A1"
         },
         {
            "Type":"Main",
            "Value":"Source",
            "Name":"B"
         },
         {
            "Type":"Main",
            "Value":"Representative",
            "Name":"Mike"
         },
         {
            "Type":"Main",
            "Value":"Animal",
            "Name":"Elephant"
         }
      ],
      "Description":"This is an example"
   }
}

请注意,description属性不是数组的一部分,它与属性,ID,OtherID和Title处于同一级别。

我正在应用以下xslt将xml转换为json。在此xml中,我声明了一个变量,该变量将包含说明并将其添加到对象的末尾

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0">
<xsl:output method="text" />

<xsl:template match="/">
    <xsl:variable name="description2" select="''" />
    {
    <xsl:for-each select="Request/Record">
        "Record": {
        "ID":"<xsl:value-of select="ID" />",
        "OtherId": "<xsl:value-of select="OtherID" />",
        "Title":"Example",
        <xsl:if test="Properties">
            "Properties": [
            <xsl:for-each select="Properties/Attribute">
                <xsl:if test="soi:Name = 'Description'">
                    <xsl:variable name="description2" select="<xsl:value-of select="Value" />" />
                    <xsl:if test="position() != last()">,</xsl:if>
                </xsl:if>
                <xsl:if test="Name != 'Description'">
                    {
                    "Type": "Main",
                    "Name": "<xsl:value-of select="Name" />",
                    "Value": "<xsl:value-of select="Value" />"
                    }
                    <xsl:if test="position() != last()">,</xsl:if>
                </xsl:if>

            </xsl:for-each>
            ]
        </xsl:if>
        }<xsl:if test="position() != last()">,</xsl:if>
    </xsl:for-each>
    <xsl:if test="description2!=''">
    ,"Description":"<xsl:value-of select="$description2"/>"
    </xsl:if>
    }
</xsl:template>

不幸的是,我得到了这个输出

{
   "Request":{
      "ID":"123456789",
      "OtherID":"ABC123",
      "Title":"Example",
      "Properties":[
         {
            "Type":"Main",
            "Value":"Source",
            "Name":"A1"
         },
         {
            "Type":"Main",
            "Value":"Source",
            "Name":"B"
         },
         {
            "Type":"Main",
            "Value":"Representative",
            "Name":"Mike"
         },
         {
            "Type":"Main",
            "Value":"Animal",
            "Name":"Elephant"
         }
      ],
      "Description":""
   }
}

描述的值是空的,因为我不知道如何在循环中重新分配变量描述的值。我使用了一个双循环来获取描述,但是效率很低。

欢迎任何建议

谢谢。

2 个答案:

答案 0 :(得分:1)

在XSLT 3(随Saxon 9.8或更高版本以及AltovaXML 2017 R3和更高版本中提供)中,您可以简单地将XML转换为xml-to-json函数https://www.w3.org/TR/xpath-functions/#func-xml-to-json期望的XML格式,然后应用该函数:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns="http://www.w3.org/2005/xpath-functions"
    expand-text="yes"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:output method="text"/>

  <xsl:template match="Request">
      <xsl:variable name="json-xml">
          <map>
              <xsl:apply-templates/>
          </map>
      </xsl:variable>
      <xsl:value-of select="xml-to-json($json-xml, map { 'indent' : true() })"/>
  </xsl:template>

  <xsl:template match="Record">
      <map key="{local-name()}">
          <xsl:apply-templates/>
      </map>
  </xsl:template>

  <xsl:template match="ID | OtherID | Title">
      <string key="{local-name()}">{.}</string>
  </xsl:template>

  <xsl:template match="Properties">
      <array key="{local-name()}">
          <xsl:apply-templates select="Attribute[not(Name = 'Description')]"/>
      </array>
      <string key="Description">{Attribute[Name = 'Description']/Value}</string>
  </xsl:template>

  <xsl:template match="Attribute">
      <map>
          <xsl:apply-templates select="@type, Value, Name"/>
      </map>
  </xsl:template>

  <xsl:template match="Attribute/@* | Attribute/*">
      <string key="{local-name()}">{.}</string>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/bnnZWz/2

使用相同的选项来区分Attribute[not(Name = 'Description')]Attribute[Name = 'Description']/Value当然也会对您的原始代码有所帮助。

答案 1 :(得分:0)

我已经在下面修改了您的原始XSLT,以便填充“说明”的值。

我注释掉了与变量$ description2相关的部分。我没有使用变量,而是使用XPath选择其中[../ Name ='Description']

的元素。

祝你好运!

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="text" />

    <xsl:template match="/">
        <!--<xsl:variable name="description2" select="''" />-->
        {
        <xsl:for-each select="Request/Record">
            "Record": {
            "ID":"<xsl:value-of select="ID" />",
            "OtherId": "<xsl:value-of select="OtherID" />",
            "Title":"Example",
            <xsl:if test="Properties">
                "Properties": [
                <xsl:for-each select="Properties/Attribute">
                    <!--<xsl:if test="soi:Name = 'Description'">
                        <xsl:variable name="description2" select="<xsl:value-of select="Value" />" />
                            <xsl:if test="position() != last()">,</xsl:if>
                    </xsl:if>-->
                    <xsl:if test="Name != 'Description'">
                        {
                        "Type": "Main",
                        "Name": "<xsl:value-of select="Name" />",
                        "Value": "<xsl:value-of select="Value" />"
                        }
                        <xsl:if test="position() != last()">,</xsl:if>
                    </xsl:if>

                </xsl:for-each>
                ]
            </xsl:if>
            }<xsl:if test="position() != last()">,</xsl:if>
        </xsl:for-each>
        <xsl:if test="/Request/Record/Properties/Attribute/Value[../Name='Description']">
            ,"Description":"<xsl:value-of select="/Request/Record/Properties/Attribute/Value[../Name='Description']"/>"
        </xsl:if>
        }
    </xsl:template>
</xsl:stylesheet>