我遇到了一个问题,这个问题是从XML到JSON的再次调解,然后问题是我需要使用的库在使用JSON数组方面做得不好。基本上调解的结果是:
<Continents>
<ContinentName>
<element>North America</element>
<element>Asia</element>
</ContinentName>
</Continents>
但我想要的是一系列大陆名称:
<Continents>
<ContinentName>North America<ContinentName>
<ContinentName>Asia<ContinentName>
<Continents>
有没有办法在XSL中轻松完成这项工作?
谢谢,
伊恩
添加几个更好的示例来显示整个文档。可悲的是,关于这是通用的还是具体的问题的答案是它的具体情况。标签由我们使用的JSON库插入:
示例1,结构简单,虽然在这种情况下,只需要将Animals / element节点重命名为,但这很容易。这是我感到困惑的大陆作品。
<?xml version="1.0" encoding="UTF-8"?>
<Animals>
<element>
<SpeciesName>Grizzly Bear</SpeciesName>
<Continents>
<ContinentName>
<element>North America</element>
<element>Asia</element>
<element>Europe</element>
</ContinentName>
</Continents>
<Population>867</Population>
<href>http://fazio.loc/rest/animal/5a559e67-475b-41e8-9fdc-00359be1d4e2</href>
<Id>5a559e67-475b-41e8-9fdc-00359be1d4e2</Id>
</element>
<element>
<SpeciesName>Black Bear</SpeciesName>
<IdentificationDate>1897-10-20</IdentificationDate>
<Continents>
<ContinentName>
<element>North America</element>
<element>Europe</element>
</ContinentName>
</Continents>
<Population>11054</Population>
<href>http://fazio.loc/rest/animal/f2e020e4-93ab-4d9b-b7b2-63082e2eaf06</href>
<Id>f2e020e4-93ab-4d9b-b7b2-63082e2eaf06</Id>
</element>
</Animals>
示例2更复杂,因为LineItem数组可以包含一个或多个具有不同结果的元素:
<?xml version="1.0" encoding="UTF-8"?>
<Orders>
<element>
<Description>First Order</Description>
<Status>New</Status>
<TotalCost>$45</TotalCost>
<LineItems>
<LineItem>
<Name>Socks</Name>
<Price>$15</Price>
<Quantity>3</Quantity>
<Total>$45</Total>
</LineItem>
</LineItems>
<href>http://fazio.loc/rest/orderStatus/0d06dc7d-2491-4fa9-9e49-921b4cb9934a</href>
<Id>0d06dc7d-2491-4fa9-9e49-921b4cb9934a</Id>
</element>
<element>
<Description>First Order</Description>
<Status>New</Status>
<TotalCost>$80</TotalCost>
<LineItems>
<LineItem>
<element>
<Name>Socks</Name>
<Price>$15</Price>
<Quantity>3</Quantity>
<Total>$45</Total>
</element>
<element>
<Name>Pants</Name>
<Price>$35</Price>
<Quantity>1</Quantity>
<Total>$35</Total>
</element>
</LineItem>
</LineItems>
<href>http://fazio.loc/rest/orderStatus/c929e8bc-054a-4ffc-86b9-b42af63d5537</href>
<Id>c929e8bc-054a-4ffc-86b9-b42af63d5537</Id>
</element>
</Orders>
我真的很讨厌这样做,但我对这些消息有一个变体,建议的解决方案并不起作用。这就是内心并不深刻的地方。即文档看起来像:
<?xml version="1.0" encoding="UTF-8"?>
<Order
xmlns="http://demo.soa.com/order/1.0">
<Description >First Order</Description>
<Status >New</Status>
<TotalCost >$80</TotalCost>
<LineItems >
<LineItem>
<element>
<Name>Socks</Name>
<Price>$15</Price>
<Quantity>3</Quantity>
<Total>$45</Total>
</element>
<element>
<Name>Pants</Name>
<Price>$35</Price>
<Quantity>1</Quantity>
<Total>$35</Total>
</element>
</LineItem>
</LineItems>
<href >http://fazio.loc/rest/orderStatus/c929e8bc-054a-4ffc-86b9-b42af63d5537</href>
<Id >c929e8bc-054a-4ffc-86b9-b42af63d5537</Id>
</Order>
我无法理解与众不同之处,但在这种情况下,似乎并不匹配,因此不会被替换。
答案 0 :(得分:2)
这是一个可能的解决方案:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<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="*[child::element][parent::*]">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="element">
<xsl:element name="{name(parent::*)}">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
此XSLT样式表包含三个模板。第一个称为身份转换,因为它只是将任何节点(属性,命名空间,注释,处理指令和元素)从源树复制到结果树。
第二个模板跳过复制元素如果它有一个element
子,那么如果它不是根节点(它有一个父母)。内部数组遵循模式Continents/ContinentName/element
,LineItems/LineItem/element
,但与根元素不同:Orders/element
(而不是Orders/Order/element
或类似的东西) 。为了弥补这一点,元素是重复的,因此生成的XML格式正确。
第三个模板与element
匹配,并在其位置复制parent
元素的名称(在第二个模板中跳过。
以下是一些可以在线试验的工作小提琴:
编辑1 - 更改元素的名称:由于源中没有Order
或Animal
,因此根目录是Orders/Order
而不是Orders/Orders
,我们可以制作从父级复制的元素名称并切断s
(当然,它不会像Wolves/Wolf
这样的集合很好地工作) 。只需将此模板添加到样式表:
<xsl:template match="element[parent::*[not(parent::*)]]">
<xsl:element name="{substring(name(parent::*),1,string-length(name(parent::*))-1)}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
此模板选择其父级没有父级(父级是 root 节点)的element
个节点,并将其替换为父级的名称减去最后一个字符(如果父级是{ {1}},它会创建Animals
;如果父项为Animal
,则会创建Root
)
<强> Fiddle no. 3 强>
编辑2 - 添加默认命名空间:要向整个文档添加默认命名空间,您只需要1)将Roo
添加到xmlns="your-namespace"
和2)以匹配root并创建<xsl:stylesheet>
,在<xsl:element>
属性中提供相同的命名空间。只需将此模板添加到样式表中即可:
namespace
<强> Fiddle no. 4 强>
编辑3 - 处理现有命名空间:您的上一个示例不起作用,因为它已经声明了命名空间。样式表中任何未加前缀的元素选择器都被视为属于 no namespace 。要从源中选择属于<xsl:template match="*">
<xsl:element namespace="your-namespace" name="{name(.)}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
的{{1}}元素,您必须在样式表中再次声明该命名空间,这次使用前缀:
element
前缀所有显式选项。在样式表中,使用通配符选择所有元素, {http://demo.soa.com/order/1.0}:element
除外。所以你只需要为<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns="http://demo.soa.com/order/1.0" <!-- for the output tree -->
xmlns:demo="http://demo.soa.com/order/1.0"> <!-- for use in XPath input -->
:
element
和
element
以及<xsl:template match="*[child::demo:element][parent::*]"> ...
出现在编辑中添加的额外模板中的任何其他位置。
通常推荐的解决方案。在您的情况下,由于样式表必须处理不同的来源,可能位于不同的名称空间,而<xsl:template match="demo:element">
元素不应该是它的一部分(它&#39;由其他软件引入的外来对象),那么最佳方法可能是忽略命名空间。您可以使用XPath通过选择使用通配符的节点,然后在谓词中与其本地名称进行比较来实现。
您只需要将每个出现的element
替换为:
element
例如:
element
(BTW *[local-name()='element']
和<xsl:template match="*[child::*[local-name()='element']][parent::*]">
意思相同:我只是为了清晰起见而想要使轴明确,但我可以将其删除)
<强> Fiddle no. 5 强>
如果你总是在你的源中有一个命名空间,并且你只想将它复制到结果中,那么这个样式表将不会为你做到这一点。您仍然必须在样式表中声明它。然而, 是一个解决方案,它包括使用child::element
轴在创建每个新元素时将源中声明的名称空间复制到结果中:
element
如果您的源中未声明默认命名空间,则此解决方案将失败。
<强> Fiddle no. 6 强>