需要帮助使用xslt在rootnode中对齐属性值

时间:2017-10-01 16:28:26

标签: xslt-1.0 xslt-2.0

非常感谢您的建议和答案。

下面是我的源代码

<?xml version="1.0" encoding="UTF-8"?>
<PurchaseOrderDocument creationDate="2017-09-26T18:37:48.837Z" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
      xmlns:dssuid="urn:autoid:specification:universal:Identifier:xml:schema:1" 
      xmlns:dsscore="urn:autoid:specification:interchange:PMLCore:xml:schema:1">
    <PurchaseQuery>
        <EventDate>20170926</EventDate>
        <bizLocation>
            <id>urn:ddd:id:sgln:0315563.00000.0</id>
        </bizLocation>
        <Serialization>
            <BATCH_ID>3091145AB</BATCH_ID>
            <EXPIRATION_DATE>20190504</EXPIRATION_DATE>
            <PRODUCTION_DATE>20170505</PRODUCTION_DATE>
            <GTIN>04028691544401</GTIN>
            <Count>8088</Count>
        </Serialization>
    </PurchaseQuery>
</PurchaseOrderDocument>

此源xml具有不需要的命名空间 我的实际目标应如下所示

<?xml version="1.0" encoding="UTF-8"?>
<ns0:PurchaseOrderDocument xmlns:ns0="urn:global:mns:PurchaseOrder" 
                           creationDate="2017-09-26T18:37:48.837Z">
  <PurchaseQuery>
    <EventDate>20170926</EventDate>
    <bizLocation>
      <id>urn:ddd:id:sgln:0315563.00000.0</id>
    </bizLocation>
    <Serialization>
      <BATCH_ID>3091145AB</BATCH_ID>
      <EXPIRATION_DATE>20190504</EXPIRATION_DATE>
      <PRODUCTION_DATE>20170505</PRODUCTION_DATE>
      <GTIN>04028691544401</GTIN>
      <Count>8088</Count>
    </Serialization>
  </PurchaseQuery>
</ns0:PurchaseOrderDocument>

我尝试应用下面的XSLT,但属性不是目标所期望的顺序

<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="2.0" encoding="UTF-8" />
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">

        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*" priority="1">

        <xsl:element name="{local-name()}" >
            <xsl:namespace name="ns0" 
                           select="'urn:global:mns:PurchaseOrder'"/> 
            <xsl:apply-templates select="@*|node()"/>

        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

应用XSLT后的输出如下

<?xml version='1.0' encoding='UTF-8' ?>
<PurchaseOrderDocument xmlns:ns0="urn:global:mns:PurchaseOrder" 
                       creationDate="2017-09-26T18:37:48.837Z">
  <PurchaseQuery>
    <EventDate>20170926</EventDate>
    <bizLocation>
      <id>urn:ddd:id:sgln:0315563.00000.0</id>
    </bizLocation>
    <Serialization>
      <BATCH_ID>3091145AB</BATCH_ID>
      <EXPIRATION_DATE>20190504</EXPIRATION_DATE>
      <PRODUCTION_DATE>20170505</PRODUCTION_DATE>
      <GTIN>04028691544401</GTIN>
      <Count>8088</Count>
    </Serialization>
  </PurchaseQuery>
</PurchaseOrderDocument>

我尝试了许多方法在命名空间之前获取属性创建日期但是徒劳无功。我无法理解我在哪里丢失。我见过很多博客但不幸的是我无法找到如何保留属性(这是动态值)在根节点中进入正确的位置,就像在目标结构中一样。这个逻辑对我来说有点重要。请建议我应该在XSLT代码中包含什么以获得实际的目标结构。任何帮助都将是非常感谢。

1 个答案:

答案 0 :(得分:1)

序列化XML中的属性顺序(为此目的,名称空间声明计为属性)被认为没有意义,并且无法使用XSLT进行控制。我所知道的大多数其他序列化库也是如此。

Saxon确实有一个扩展名(xsl:output / @ saxon:attribute-order)来控制非命名空间属性的顺序,但它不会影响命名空间声明相对于属性的显示位置。

我不得不问为什么这么重要。如果您使用一致的解析器读取XML,那么它将不关心属性出现的顺序,如果您在不使用一致的解析器的情况下读取XML,那么您就犯了一个错误。

And also please help me how I can add prefix ns0: for each target line.

那是另一回事。但你不应该想“如何添加前缀”,你应该考虑“如何将输出元素放入命名空间urn:global:mns:PurchaseOrder”。好吧,有三种创建输出元素的方法:

  • xsl:copy将始终创建一个与原始名称相同的元素(名称空间URI加本地名称),因此不适合此处。

  • 文字结果元素创建一个与样式表中的指令具有相同名称的元素(名称空间URI加本地名称)

  • xsl:element有两个属性,名称和命名空间,允许您控制输出元素名称的两个部分。