[英]How to transform unordered elements in xml to match an xsd:sequence order?
與同等命名子元素的答案相比,我嘗試轉換以下內容:
<Person>
<Address>5</Address>
<Firstname>1234567890</Firstname>
<Lastname>
<MaidenName>The BFG</MaidenName>
<StageName>GFB eht</StageName>
</Lastname>
</Person>
進入所需結果:
<Person>
<Firstname>1234567890</Firstname>
<Lastname>
<StageName>GFB eht</StageName>
<MaidenName>The BFG</MaidenName>
</Lastname>
<Address>5</Address>
</Person>
但是繼續出現以下錯誤:
xml2xml.xsl的第47行的xsl:element錯誤:XTDE0820:提供的元素名稱是零長度的字符串
元素如何以正確的順序傳遞和插入?
所需結果符合所提供的XML模式:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="Person" type="Person"/>
<xs:complexType name="Person">
<xs:sequence>
<xs:element name="Firstname" type="xs:string"/>
<xs:element name="Lastname" type="Lastname"/>
<xs:element name="Address" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Lastname">
<xs:sequence>
<xs:element name="StageName" type="xs:string"/>
<xs:element name="MaidenName" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
我正在使用這種轉換,它是從您獲得的, 您可以轉換無序xml以匹配xsd:sequence順序嗎? xsdsequence-order並嘗試適應:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kxsElemByName" match="xs:complexType" use="@name"/>
<xsl:variable name="vSchema" select=
"document('file:///D:/xslt/test/schema.xsd')"/>
<xsl:variable name="vDoc" select="/"/>
<xsl:template match="/*">
<xsl:variable name="vElem" select="."/>
<xsl:for-each select="$vSchema">
<xsl:apply-templates select=
"key('kxsElemByName', name($vElem))">
<xsl:with-param name="pElement" select="$vElem"/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="xs:complexType">
<xsl:param name="pElement"/>
<xsl:element name="{name($pElement)}">
<xsl:apply-templates mode="generate"
select="xs:sequence/*">
<xsl:with-param name="pParent" select="$pElement"/>
</xsl:apply-templates>
</xsl:element>
</xsl:template>
<xsl:template match="xs:element" mode="generate">
<xsl:param name="pParent"/>
<xsl:variable name="vProp" select=
"$pParent/*[local-name(.) = local-name(current())]/*"/>
<xsl:element name="{local-name($vProp)}">
<xsl:value-of select="$vProp"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
我認為這從根本上是錯誤的。 您想要一種適用於任何模式的通用解決方案,或者想要一種針對某個特定模式的解決方案。 目前,您正在嘗試從架構中提取結構,但是您已經對架構的編寫方式做出了許多假設,以至於解決方案非常脆弱(我什至不會嘗試找到該架構)。特定錯誤)。 例如,您假設:
這些假設是如此嚴格,以至於您真的可以將規則硬編碼為XSLT代碼,而不是嘗試從架構中提取它們。
如果要正確執行此操作,請不要嘗試從源模式文檔中進行工作,而應從模式編譯器的輸出中進行工作-例如,Saxon模式處理器生成的SCM文件或可以訪問的模式信息。在XSLT中使用saxon:schema()擴展功能。
我不確定這是否真的是您所期望的,但是無論如何-通過這種方式可以創建所需的輸出結構:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="Person">
<xsl:element name="Person">
<xsl:copy-of select="Firstname" />
<xsl:copy-of select="Lastname" />
<xsl:copy-of select="Address" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
通過重構所需元素並復制所有子節點來實現排序。
假設您只是想根據XSD調整順序,請嘗試以下XSLT。 對於源XML中的每個元素,它都會檢查以在XSD中查找xs:element
,對於該xs:element
是否為復雜類型。 如果是這樣,那么它將相應地對子元素進行排序。
根據邁克爾的說法,這仍然非常脆弱。 凱的答案,盡管它不再依賴於與元素名稱匹配的復雜類型的名稱。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" indent="yes" />
<xsl:key name="kxsElemByName" match="xs:element" use="@name"/>
<xsl:key name="kxsTypeByName" match="xs:complexType" use="@name"/>
<xsl:variable name="vSchema" select="document('file:///D:/xslt/test/schema.xsd')"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*" priority="2">
<xsl:variable name="current" select="." />
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:for-each select="$vSchema">
<xsl:variable name="element" select="key('kxsElemByName', name($current))" />
<xsl:variable name="complex" select="key('kxsTypeByName', $element/@type)" />
<xsl:choose>
<xsl:when test="$complex">
<xsl:for-each select="$complex/xs:sequence/xs:element">
<xsl:apply-templates select="$current/*[name() = current()/@name]" />
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$current/node()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.