我回答了我自己的问题,但希望能就如何提高它的速度、清晰度或更实用的解决方案提供建设性的反馈。::)
如果你想了解我问题的原意,请跳到~编辑~或阅读它。
简而言之,我有一个XML数据集,它看起来如下所示:
<org> <!-- Organization -->
<dep> <!-- Department -->
<nm>Department</nm> <!-- Department Name -->
<emps> <!-- Head Department Employees -->
<emp> <!-- One of the Head Employees -->
<!-- Some Data, ie., L Name, F Name, and etc. (Omitted) -->
</emp>
<emp>
<!-- Omitted -->
</emp>
</emps>
<deps> <!-- So-called "Sub-Departments" -->
<dep>
<nm>Sub Department</nm>
<emps>
<emp>
<!-- Omitted -->
</emp>
</emps>
</dep>
</deps>
</dep>
</org>这是一个很小的样本,但关键是一个部门可以任意数量的雇员和任何数量的分部门。通常情况下,这样的数据集将是最底层的,高层(领导者)的人数很少,而当你深入到下属部门时,数据就会越来越多。我一直在努力做的是--事实上,今天刚刚取得了半突破--想出了如何将XML数据集转换成一个不起眼的HTML组织结构图。
我最初想出的嵌套div具有战略性放置的"float: left“和”清除:两者都“的样式,看起来如下所示:
+-------------------------------------------------------+
| Dep |
| +------------------------+ |
| | +--------+ +---------+ | |
| | | Emp | | Emp | | |
| | +--------+ +---------+ | |
| +------------------------+ |
| +---------------------------------------------------+ |
| | +----------------------+ +----------------------+ | |
| | | Dep | | Dep | | |
| | | +--------+ +-------+ | | +--------+ +-------+ | | |
| | | | Emp | | Emp | | | | Emp | | Emp | | | |
| | | +--------+ +-------+ | | +--------+ +-------+ | | |
| | +----------------------+ +----------------------+ | |
| +---------------------------------------------------+ |
+-------------------------------------------------------+为我粗俗的ASCII艺术道歉。
我已经绞尽脑汁想出一个XSLT转换,它可以产生这样的结果:
+-------------------------------------------------------+
| Dep |
| +------------------------+ |
| | +--------+ +---------+ | |
| | | Emp | | Emp | | |
| | +--------+ +---------+ | |
| +------------------------+ |
| +---------------------------------------------------+ |
| | +----------------------+ +----------------------+ | |
| | | Dep | | Dep | | |
| | | +--------+ +-------+ | | +--------+ +-------+ | | |
| | | | Emp | | Emp | | | | Emp | | Emp | | | |
| | | +--------+ +-------+ | | +--------+ +-------+ | | |
| | +----------------------+ +----------------------+ | |
| +---------------------------------------------------+ |
+-------------------------------------------------------+浮动div并不能做到这一点,而当绝对定位工作时,唯一具有固定宽度的div是员工div,所以我需要以某种方式获得所有包含元素的总宽度,以适当地调整每个部门、部门和员工div的大小。今天,我的想法是,我所需要做的就是清点每个部门部门的所有底层员工部门,因为组织结构图往往会自上而下地展开:
<xsl:template match="dep">
<!-- Just assuming that dep's, deps's, and emps's have no margin, padding, or border
for the sake of keeping this example simpler -->
<xsl:variable name="emp_count"
select="count(descendant::emp[parent::emps/parent::dep[count(child::deps)=0]])"/>
<xsl:variable name="width" select="$emp_count * $emp_width"/>
<xsl:variable name="mleft" select="$width div 2"/>
<div style="position: absolute; left: 50%; width: {$width}px;
margin-left: -{$mleft}px;">
<xsl:apply-templates/>
</div>
</xsl:template>简单地说,虽然上面的内容遗漏了很多,但它起作用了,除非我有任何类型的字体。但!问题出在这里。这就假设该组织遵循了由来已久的低端重量级传统。如何转换应该输出如下内容的组织文档?
+---------------------------------------------------------------+
| Dep |
| +-----------------------------------------------------------+ |
| | +--------+ +---------+ +--------+ +---------+ +---------+ | |
| | | Emp | | Emp | | Emp | | Emp | | Emp | | |
| | +--------+ +---------+ +--------+ +---------+ +---------+ | |
| +-----------------------------------------------------------+ |
| +---------------------------------------------------+ |
| | +----------------------+ +----------------------+ | |
| | | Dep | | Dep | | |
| | | +--------+ +-------+ | | +--------+ +-------+ | | |
| | | | Emp | | Emp | | | | Emp | | Emp | | | |
| | | +--------+ +-------+ | | +--------+ +-------+ | | |
| | +----------------------+ +----------------------+ | |
| +---------------------------------------------------+ |
+---------------------------------------------------------------+啊..。没有什么比一个角落的案子来毁掉我最初以为能解决整个星期困扰我大脑的问题了。事实上,这种情况可能永远不会出现。实际上,也许使用嵌套表可能比使用div更容易。
但是现在我在这里我在想..。
考虑到这个角落的情况,我们如何计算高层部门div的宽度,同时也要记住这个角落的情况可能会在层次结构中发生不止一次和任意的深度?
~编辑~
我想转一下这个XML源文档:
<?xml version="1.0" encoding="UTF-8"?>
<dep>
<nm>Dep</nm>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<dep>
<nm>Sub Dep 1</nm>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<dep>
<nm>Sub Dep 1-1</nm>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
</dep>
<dep>
<nm>Sub Dep 1-2</nm>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
</dep>
</dep>
<dep>
<nm>Sub Dep 2</nm>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<dep>
<nm>Sub Dep 2-1</nm>
<emp>
<nm>Emp</nm>
</emp>
</dep>
<dep>
<nm>Sub Dep 2-2</nm>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
</dep>
</dep>
<dep>
<nm>Sub Dep 3</nm>
<emp>
<nm>Emp</nm>
</emp>
</dep>
<dep>
<nm>Sub Dep 4</nm>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<dep>
<nm>Sub Dep 4-1</nm>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<dep>
<nm>Sub Dep 4-1-1</nm>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<dep>
<nm>Sub Dep 4-1-1-1</nm>
<emp>
<nm>Emp</nm>
</emp>
</dep>
<dep>
<nm>Sub Dep 4-1-1-2</nm>
<emp>
<nm>Emp</nm>
</emp>
</dep>
</dep>
</dep>
<dep>
<nm>Sub Dep 4-2</nm>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
</dep>
</dep>
</dep>...into这个XML结果文档:
<?xml version="1.0" encoding="UTF-8"?>
<deps emps-wide="16">
<dep emps-wide="16">
<nm>Dep</nm>
<emps emps-wide="3">
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
</emps>
<deps emps-wide="16">
<dep emps-wide="5">
<nm>Sub Dep 1</nm>
<emps emps-wide="2">
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
</emps>
<deps emps-wide="5">
<dep emps-wide="3">
<nm>Sub Dep 1-1</nm>
<emps emps-wide="3">
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
</emps>
<deps emps-wide="0"/>
</dep>
<dep emps-wide="2">
<nm>Sub Dep 1-2</nm>
<emps emps-wide="2">
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
</emps>
<deps emps-wide="0"/>
</dep>
</deps>
</dep>
<dep emps-wide="4">
<nm>Sub Dep 2</nm>
<emps emps-wide="4">
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
</emps>
<deps emps-wide="3">
<dep emps-wide="1">
<nm>Sub Dep 2-1</nm>
<emps emps-wide="1">
<emp>
<nm>Emp</nm>
</emp>
</emps>
<deps emps-wide="0"/>
</dep>
<dep emps-wide="2">
<nm>Sub Dep 2-2</nm>
<emps emps-wide="2">
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
</emps>
<deps emps-wide="0"/>
</dep>
</deps>
</dep>
<dep emps-wide="1">
<nm>Sub Dep 3</nm>
<emps emps-wide="1">
<emp>
<nm>Emp</nm>
</emp>
</emps>
<deps emps-wide="0"/>
</dep>
<dep emps-wide="6">
<nm>Sub Dep 4</nm>
<emps emps-wide="2">
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
</emps>
<deps emps-wide="6">
<dep emps-wide="4">
<nm>Sub Dep 4-1</nm>
<emps emps-wide="3">
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
</emps>
<deps emps-wide="4">
<dep emps-wide="4">
<nm>Sub Dep 4-1-1</nm>
<emps emps-wide="4">
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
</emps>
<deps emps-wide="2">
<dep emps-wide="1">
<nm>Sub Dep 4-1-1-1</nm>
<emps emps-wide="1">
<emp>
<nm>Emp</nm>
</emp>
</emps>
<deps emps-wide="0"/>
</dep>
<dep emps-wide="1">
<nm>Sub Dep 4-1-1-2</nm>
<emps emps-wide="1">
<emp>
<nm>Emp</nm>
</emp>
</emps>
<deps emps-wide="0"/>
</dep>
</deps>
</dep>
</deps>
</dep>
<dep emps-wide="2">
<nm>Sub Dep 4-2</nm>
<emps emps-wide="2">
<emp>
<nm>Emp</nm>
</emp>
<emp>
<nm>Emp</nm>
</emp>
</emps>
<deps emps-wide="0"/>
</dep>
</deps>
</dep>
</deps>
</dep>
</deps>为了完整起见,下面是我用来生成大部分XML结果文档的XLST转换:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:call-template name="recurse-deps"/>
</xsl:template>
<xsl:template name="recurse-deps">
<deps emps-wide="">
<xsl:for-each select="dep">
<dep emps-wide="">
<nm><xsl:value-of select="nm"/></nm>
<emps emps-wide="">
<xsl:for-each select="emp">
<emp>
<nm><xsl:value-of select="nm"/></nm>
</emp>
</xsl:for-each>
</emps>
<xsl:call-template name="recurse-deps"/>
</dep>
</xsl:for-each>
</deps>
</xsl:template>
</xsl:stylesheet>请注意,我已经概括了我原来的问题。我们甚至不关心如何将其显示为组织结构图。这并不是我想要学习用XSLT解决的问题。
还要注意,我必须编辑XML结果文档,因为我--显然--不太知道如何编写XSLT样式表来生成我想要的东西。否则,我不会在这里问问题。:)
下面是我在试图用XSLT来表达时遇到的许多困难,以及为什么在运行转换之后我必须手动编辑XML结果文档:
那么,我想在XSLT中解决的问题是如何将一个泛型和递归结构的XML源文档转换为XML结果文档,其中每个(或大多数)元素都应该附加某种计算值,而这些值依赖于其子元素的相同或相似的计算值.等等..。等等..。一直到任何可能是“叶节点”的地方。
快速编辑:更多地考虑这个问题,类似的例子是将“文件系统”XML源文档转换为XML结果文档,其中向每个“文件夹”添加“文件计数”属性,显示其中的文件总数及其“子文件夹”及其“子文件夹”等等。
对学习如何做这件事有什么帮助--甚至.不是的。尤其是如果有不止一种惯用的方法去做
发布于 2012-08-13 04:40:35
我想出了一种方法来做我一直想做的事。
这个XSLT样式表将XML文档转换为所需的XML结果文档(在我的~EDIT~之后的问题中找到)。
在我看来,可能有一个更好或更地道的解决办法。我发现多次迭代XML文档,从一个转换到下一个转换将结果树片段流水线化,并且每次迭代只进行简单的更改,这帮助我找到了这个解决方案。如果我不采用这种方法,我很难想象这个XSLT样式表会有多复杂。我敢说我不可能一举做到这一点。
即使如此,我相信仍有改进的余地(速度和/或清晰度)。这是为了帮助其他可能处理与我类似的问题的人,或者是建设性的批评和改进,我也希望这样做:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version = "1.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl = "urn:schemas-microsoft-com:xslt"
xmlns:exsl = "http://exslt.org/common"
extension-element-prefixes = "exsl">
<xsl:output method = "xml"
omit-xml-declaration = "no"
indent = "yes"
encoding = "UTF-8"/>
<xsl:template match = "/">
<xsl:variable name = "boxed-emps-and-deps">
<xsl:call-template name = "box-emps-and-deps"/>
</xsl:variable>
<xsl:variable name = "added-emp-count-to-emps">
<xsl:call-template name = "add-emp-count-to-emps">
<xsl:with-param name = "last-pass" select = "$boxed-emps-and-deps"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name = "added-emp-count-to-dep">
<xsl:call-template name = "add-emp-count-to-dep">
<xsl:with-param name = "last-pass" select = "$added-emp-count-to-emps"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name = "added-emp-count-to-deps">
<xsl:call-template name = "add-emp-count-to-deps">
<xsl:with-param name = "last-pass" select = "$added-emp-count-to-dep"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name = "recurred-dep-and-deps-emp-counts">
<xsl:call-template name = "recur-dep-and-deps-emp-counts">
<xsl:with-param name = "last-pass" select = "$added-emp-count-to-deps"/>
</xsl:call-template>
</xsl:variable>
<xsl:copy-of select="exsl:node-set( $recurred-dep-and-deps-emp-counts )"/>
</xsl:template>
<xsl:template name = "box-emps-and-deps">
<deps>
<xsl:for-each select = "dep">
<dep>
<xsl:copy-of select = "nm"/>
<emps>
<xsl:for-each select = "emp">
<xsl:copy-of select = "."/>
</xsl:for-each>
</emps>
<xsl:call-template name = "box-emps-and-deps"/>
</dep>
</xsl:for-each>
</deps>
</xsl:template>
<xsl:template name = "add-emp-count-to-emps">
<xsl:param name = "last-pass"/>
<xsl:for-each select = "exsl:node-set( $last-pass )/node()">
<xsl:copy>
<xsl:if test = "name( . ) = 'emps'">
<xsl:attribute name = "emp-cnt">
<xsl:value-of select = "count( emp )"/>
</xsl:attribute>
</xsl:if>
<xsl:call-template name="add-emp-count-to-emps">
<xsl:with-param name = "last-pass" select = "."/>
</xsl:call-template>
</xsl:copy>
</xsl:for-each>
</xsl:template>
<xsl:template name = "add-emp-count-to-dep">
<xsl:param name = "last-pass"/>
<xsl:for-each select = "exsl:node-set( $last-pass )/node()|@*">
<xsl:copy>
<xsl:if test = "name( . ) = 'dep'">
<xsl:attribute name = "emp-cnt">
<xsl:value-of select = "emps/@emp-cnt"/>
</xsl:attribute>
</xsl:if>
<xsl:call-template name="add-emp-count-to-dep">
<xsl:with-param name = "last-pass" select = "."/>
</xsl:call-template>
</xsl:copy>
</xsl:for-each>
</xsl:template>
<xsl:template name = "add-emp-count-to-deps">
<xsl:param name = "last-pass"/>
<xsl:for-each select = "exsl:node-set( $last-pass )/node()|@*">
<xsl:copy>
<xsl:if test = "name( . ) = 'deps'">
<xsl:attribute name = "emp-cnt">
<xsl:value-of select = "sum( dep/@emp-cnt )"/>
</xsl:attribute>
</xsl:if>
<xsl:call-template name="add-emp-count-to-deps">
<xsl:with-param name = "last-pass" select = "."/>
</xsl:call-template>
</xsl:copy>
</xsl:for-each>
</xsl:template>
<xsl:template name = "recur-dep-and-deps-emp-counts">
<xsl:param name = "last-pass"/>
<xsl:variable name = "top-deps-emp-count" select="exsl:node-set( $last-pass )/deps/@emp-cnt"/>
<xsl:variable name = "redid-dep-emp-count">
<xsl:call-template name = "redo-dep-emp-count">
<xsl:with-param name = "last-pass" select = "$last-pass"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name = "redid-deps-emp-count">
<xsl:call-template name = "redo-deps-emp-count">
<xsl:with-param name = "last-pass" select = "$redid-dep-emp-count"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name = "new-top-deps-emp-count" select = "exsl:node-set( $redid-deps-emp-count)/deps/@emp-cnt"/>
<xsl:choose>
<xsl:when test = "$top-deps-emp-count = $new-top-deps-emp-count">
<xsl:copy-of select = "$redid-deps-emp-count"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name = "recur-dep-and-deps-emp-counts">
<xsl:with-param name = "last-pass" select = "$redid-deps-emp-count"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name = "redo-dep-emp-count">
<xsl:param name = "last-pass"/>
<xsl:for-each select = "exsl:node-set( $last-pass )/node()|@*">
<xsl:choose>
<xsl:when test = "name( . ) = 'emp-cnt' and name( ./.. ) = 'dep'">
<xsl:attribute name = "emp-cnt">
<xsl:choose>
<xsl:when test = "./../deps/@emp-cnt > ./../emps/@emp-cnt">
<xsl:value-of select = "./../deps/@emp-cnt"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select = "./../emps/@emp-cnt"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:call-template name="redo-dep-emp-count">
<xsl:with-param name = "last-pass" select = "."/>
</xsl:call-template>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<xsl:template name = "redo-deps-emp-count">
<xsl:param name = "last-pass"/>
<xsl:for-each select = "exsl:node-set( $last-pass )/node()|@*">
<xsl:choose>
<xsl:when test = "name( . ) = 'emp-cnt' and name( ./.. ) = 'deps'">
<xsl:attribute name = "emp-cnt">
<xsl:value-of select = "sum( ./../dep/@emp-cnt )"/>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:call-template name="redo-deps-emp-count">
<xsl:with-param name = "last-pass" select = "."/>
</xsl:call-template>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>https://stackoverflow.com/questions/11911337
复制相似问题