【问题标题】:Using XSLT in order to return an empty valid JSON object使用 XSLT 以返回一个空的有效 JSON 对象
【发布时间】:2015-04-23 08:04:31
【问题描述】:

我们正在使用一个返回 XML 的 Web 服务,并且我们正在使用 XSLT 来对日期进行排序并仅将其中的一部分发送到移动客户端。返回给客户端的数据是 JSON 解析的。 在给定参数上,服务返回一个空 XML - 如问题末尾所示。

在这种情况下,我们要做的是弄清楚如何向客户端返回一个空的有效 JSON 对象(即 [])。目前,我们无法更改 Web 服务本身的任何内容。任何想法都会很有帮助。

XML:

<?xml version="1.0" encoding="utf-8"?>
<DataSet xmlns="http://tempuri.org/">
  <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:Locale="">
      <xs:complexType>
        <xs:choice maxOccurs="unbounded">
          <xs:element name="Events">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="Name" type="xs:string" minOccurs="0" />
                <xs:element name="boneId" type="xs:int" minOccurs="0" />
                <xs:element name="nsId" type="xs:int" minOccurs="0" />
                <xs:element name="objId" type="xs:int" minOccurs="0" />
                <xs:element name="fileName" type="xs:string" minOccurs="0" />
                <xs:element name="Date" type="xs:dateTime" minOccurs="0" />
                <xs:element name="ArieId" type="xs:int" minOccurs="0" />
                <xs:element name="EventPlaceName" type="xs:string" minOccurs="0" />
                <xs:element name="City" type="xs:int" minOccurs="0" />
                <xs:element name="PlaceFileName" type="xs:string" minOccurs="0" />
                <xs:element name="PlaceBoneId" type="xs:int" minOccurs="0" />
                <xs:element name="PlaceNsId" type="xs:int" minOccurs="0" />
                <xs:element name="PlaceObjId" type="xs:int" minOccurs="0" />
                <xs:element name="TourName" type="xs:string" minOccurs="0" />
                <xs:element name="TimeStart" type="xs:string" minOccurs="0" />
                <xs:element name="TimeEnd" type="xs:string" minOccurs="0" />
                <xs:element name="Genre" type="xs:int" minOccurs="0" />
                <xs:element name="Genre_Name" type="xs:string" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:schema>
  <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" />
</DataSet>

XSLT:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:h="http://www.w3.org/1999/xhtml">
    <xsl:output method="text"/>
    <xsl:template match="Events">
        {
            'Items': [
                <xsl:for-each select="//Events">                                
                    {

                        'Name':             '<xsl:value-of select="Name"/>',
                        'Date':             '<xsl:value-of select="Date"/>',
                        'PlaceName':        '<xsl:value-of select="EventPlaceName"/>',
                        'boneId':           '<xsl:value-of select="boneId"/>',
                        'objId':            '<xsl:value-of select="objId"/>',
                        'PlaceNsId':        '<xsl:value-of select="PlaceNsId"/>',
                        'PlaceObjId':       '<xsl:value-of select="PlaceObjId"/>',
                        'StartPoint':       '<xsl:value-of select="StartPoint"/>',
                        'Description':      '<xsl:value-of select="Description"/>',
                        'Telephone':        '<xsl:value-of select="Telephone"/>'
                    },
                </xsl:for-each>
            ]       
        }
    </xsl:template>

</xsl:stylesheet>

来自服务的“常规”XML 响应:

<?xml version="1.0" encoding="utf-8"?>
<DataSet xmlns="http://tempuri.org/">
  <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:Locale="">
      <xs:complexType>
        <xs:choice maxOccurs="unbounded">
          <xs:element name="Events">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="Name" type="xs:string" minOccurs="0" />
                <xs:element name="boneId" type="xs:int" minOccurs="0" />
                <xs:element name="nsId" type="xs:int" minOccurs="0" />
                <xs:element name="objId" type="xs:int" minOccurs="0" />
                <xs:element name="fileName" type="xs:string" minOccurs="0" />
                <xs:element name="Date" type="xs:dateTime" minOccurs="0" />
                <xs:element name="ArieId" type="xs:int" minOccurs="0" />
                <xs:element name="EventPlaceName" type="xs:string" minOccurs="0" />
                <xs:element name="City" type="xs:int" minOccurs="0" />
                <xs:element name="PlaceFileName" type="xs:string" minOccurs="0" />
                <xs:element name="PlaceBoneId" type="xs:int" minOccurs="0" />
                <xs:element name="PlaceNsId" type="xs:int" minOccurs="0" />
                <xs:element name="PlaceObjId" type="xs:int" minOccurs="0" />
                <xs:element name="TourName" type="xs:string" minOccurs="0" />
                <xs:element name="TimeStart" type="xs:string" minOccurs="0" />
                <xs:element name="TimeEnd" type="xs:string" minOccurs="0" />
                <xs:element name="Genre" type="xs:int" minOccurs="0" />
                <xs:element name="Genre_Name" type="xs:string" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:schema>
  <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
    <NewDataSet xmlns="">
      <Events diffgr:id="Events1" msdata:rowOrder="0">
        <Name>Name</Name>
        <boneId>1855</boneId>
        <nsId>305</nsId>
        <objId>28</objId>
        <fileName>tours_item_show.aspx</fileName>
        <ArieId>1</ArieId>
        <EventPlaceName>Place name</EventPlaceName>
        <City>392</City>
        <PlaceFileName>show_item_place.aspx</PlaceFileName>
        <PlaceBoneId>1563</PlaceBoneId>
        <PlaceNsId>201</PlaceNsId>
        <PlaceObjId>2574</PlaceObjId>
        <TourName>Tour name</TourName>
        <Genre>18</Genre>
        <Genre_Name>Group tours</Genre_Name>
      </Events>
    </NewDataSet>
  </diffgr:diffgram>
</DataSet>

【问题讨论】:

  • "在给定参数上,服务返回一个空 XML - 如问题末尾所示。" 我看不出你在哪里显示。这样做非常重要,因为没有空 XML 这样的东西。如果必须至少有一个根元素 - 否则它根本不是 XML。
  • 顺便说一句,我认为您错误地发布了 XSD,而不是实际 XML 响应的示例。因此,请编辑我们的问题并提供 两个 XML 输入示例:一个“常规”示例和一个“空”示例。
  • 我附加的 XML 是从服务返回的实际响应。我在原始问题中添加了“常规”。

标签: xml json xslt


【解决方案1】:

我可能误解了这个问题,但这不只是添加模板规则的问题

<xsl:template match="diffgr:diffgram">[]</xsl:template>

【讨论】:

  • 我想你已经理解了这个问题。然而,上面的规则并不能解决问题。这个想法是为有数据的情况(已经完成)和没有数据的情况制定一个模板规则,并且能够对这两种情况使用相同的 XSLT。您建议的规则在这两种情况下都失败,提供以下错误:'Namespace prefix 'diffgr' is undeclared.'
  • 抱歉,我假设您对 XSLT 了解足够多,因此知道如果您在匹配模式中使用命名空间前缀,则必须声明它。
【解决方案2】:

当您第一次将 XML 提供给包含多个事件节点的样式表时,您会意识到您不希望其中有一个 for-each。

但就主要问题而言——我们在谈论什么空虚?我的意思是,零长度文件不是有效的 XML。但是,如果您得到一个没有 Event 节点的 NewDataSet,您应该在该级别创建封闭对象,如果没有 Event,您将自动获得一个空对象。大致如下:

<xsl:template match="NewDataSet">
    {
    <xsl:apply-templates/>
    }
<xsl:template>

更新:

在看到附加的帖子(“常规”XML)之后,我看到您正在处理的 Web 服务多么丑陋。真的吗?他们将模式嵌入到每个响应中,即使该响应没有给您任何数据?呃。

无论如何,我之前建议的变体应该可行。似乎您可以确保收到的一件事是 diffgram 节点。所以让它成为创建封闭 JSON 对象的那个。我建议你在你的 XSL 中添加一个 xslns:diffgr 声明—— local-name() 感觉就像在欺骗我。

因此,您将按照以下方式做一些事情:

<xsl:template match="diffgr:diffgram">
    {
    <xsl:apply-templates select="NewDataSet/Events"/>
    }
</xsl:template>

【讨论】:

    【解决方案3】:

    我犹豫如何准确回答这个问题,因为即使响应包含数据,您的样式表也不会返回有效的 JSON 文档。因此,我建议您查看以下内容,并在必要时进行必要的调整。

    以下样式表:

    XSLT 1.0

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" encoding="UTF-8"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="/*">
    {<xsl:apply-templates select="*/NewDataSet"/>}
    </xsl:template> 
    
    <xsl:template match="NewDataSet">
    "Items":[<xsl:apply-templates select="Events"/>]
    </xsl:template> 
    
    <xsl:template match="Events">
        {
            "Name":             "<xsl:value-of select="Name"/>",
            "Date":             "<xsl:value-of select="Date"/>",
            "PlaceName":        "<xsl:value-of select="EventPlaceName"/>",
            "boneId":           "<xsl:value-of select="boneId"/>",
            "objId":            "<xsl:value-of select="objId"/>",
            "PlaceNsId":        "<xsl:value-of select="PlaceNsId"/>",
            "PlaceObjId":       "<xsl:value-of select="PlaceObjId"/>",
            "StartPoint":       "<xsl:value-of select="StartPoint"/>",
            "Description":      "<xsl:value-of select="Description"/>",
            "Telephone":        "<xsl:value-of select="Telephone"/>"
        }
    </xsl:template> 
    
    </xsl:stylesheet>
    

    当应用于您的第二个输入 XML 示例时,将返回:

    {
    "Items":[
        {
            "Name":             "Name",
            "Date":             "",
            "PlaceName":        "Place name",
            "boneId":           "1855",
            "objId":            "28",
            "PlaceNsId":        "201",
            "PlaceObjId":       "2574",
            "StartPoint":       "",
            "Description":      "",
            "Telephone":        ""
        }
    ]
    }
    

    这与您的样式表生成的内容不完全相同 - 但它确实通过了这里的验证:http://jsonlint.com/

    相同样式表在应用于您的第一个输入 XML 示例时,将返回:

    {}
    

    注意:我相信使用&lt;xsl:text&gt; 输出文字文本可以更好地控制空白。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-06
      • 1970-01-01
      • 2017-08-31
      • 2020-03-14
      相关资源
      最近更新 更多