XForms 重复:相同的元素名称,不同的值约束
XForms repeat: same element name, different value constraints
我正在尝试在 XForms(eXist-db 中的 XSLTForms 实现)中编辑 RDF/XML,我需要对 xf:repeat
结构中具有相同名称的元素强制执行不同的值约束。例如,我有一个 bf:subject
元素,它可以将默认 URI 作为其 @rdf:resource
属性的值,也可以将任意 URI 链接到表单中定义的其他资源(为简洁起见)我在下面提供的示例中省略了这些)。
在xf:repeat
结构中,如何区分同名元素?我可以使用将 @rdf:resource
的值限制为 xf:model
中指定的默认 URI 的谓词来处理第一种情况,但我找不到一种方法来实现对 [= =13=] 可以采用任意 URI。
注意:第二个嵌套 xf:repeat 中没有表单控件,因为 @rdf:resource 的值是使用单独的 JavaScript 库动态更新的(jsPlumb) 更新 XForms 实例。
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://localhost:8080/exist/apps/xsltforms/xsltforms.xsl" type="text/xsl"?>
<?xsltforms-options debug="yes"?>
<?css-conversion no?>
<?xml-model href="http://www.oxygenxml.com/1999/xhtml/xhtml-xforms.nvdl" schematypens="http://purl.oclc.org/dsdl/nvdl/ns/structure/1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:bf="http://bibframe.org/vocab/"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Editor</title>
<!--Model-->
<xf:model id="rdf-model">
<xf:instance id="graph">
<rdf:RDF>
<bf:Work rdf:about="">
<bf:subject rdf:resource="http://id.loc.gov/vocabulary/geographicAreas/s-ag"></bf:subject>
<bf:subject rdf:resource=""/>
</bf:Work>
</rdf:RDF>
</xf:instance>
<!-- Template -->
<xf:instance id="bf-Work-template">
<rdf:RDF>
<bf:Work rdf:about="">
<bf:subject rdf:resource="http://id.loc.gov/vocabulary/geographicAreas/s-ag"></bf:subject>
<bf:subject rdf:resource=""/>
</bf:Work>
</rdf:RDF>
</xf:instance>
</xf:model>
</head>
<body>
<div id="header">
<h1>Editor</h1>
</div>
<div id="forms">
<!-- Repeat for Work entity -->
<xf:repeat nodeset="instance('graph')/bf:Work" id="repeat-Work-graph">
<!-- Repeat bf:subject elements that have a default value. -->
<xf:repeat
nodeset="bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]">
<div style="border:solid black 1px;">
<xf:input
ref="@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']">
<xf:label>Subject</xf:label>
</xf:input>
<!-- Add new bf:subject elements that have a default value -->
<xf:trigger ref=".">
<xf:label>+</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert
nodeset="../bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]"
origin="instance('bf-Work-template')/bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]"
at="last()" position="after"></xf:insert>
</xf:action>
</xf:trigger>
<!-- Delete bf:subject elements that have a default value -->
<xf:trigger
ref=".[count(../bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]) > 1]">
<xf:label>-</xf:label>
<xf:delete ev:event="DOMActivate" nodeset="." at="last()"
if="count(../bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]) > 1"
></xf:delete>
</xf:trigger>
</div>
</xf:repeat>
<!-- Add new bf:subject elements that can take an arbitrary value -->
<xf:trigger ref="bf:subject[@rdf:resource = '']">
<xf:label>+</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="."
origin="instance('bf-Work-template')/bf:Work/bf:subject[@rdf:resource = '']"
at="last()" position="after"></xf:insert>
</xf:action>
</xf:trigger>
<!-- Delete bf:subject elements that can take an arbitrary value -->
<xf:trigger
ref="bf:subject[@rdf:resource = ''][count(../bf:subject[@rdf:resource = '']) > 1]">
<xf:label>-</xf:label>
<xf:action ev:event="DOMActivate">
<xf:delete nodeset="../bf:subject[@rdf:resource = '']" at="last()"
if="count(../bf:subject[@rdf:resource = '']) > 1"></xf:delete>
</xf:action>
</xf:trigger>
<!-- Repeat bf:subject elements that can take an arbitrary value -->
<xf:repeat nodeset="bf:subject[@rdf:resource = '']">
<div style="border:solid black 1px;">
<!-- Value of @rdf:resource is updated using jsPlumb library -->
<span class="label">Subject</span>
<br />
<span>Link to:</span>
<br />
<span class="connect-to">Work</span>
<br />
<span class="connect-to">Topic</span>
<br />
<span class="connect-to">Place</span>
</div>
</xf:repeat>
</xf:repeat>
</div>
</body>
</html>
目前,默认的 URI 都来自同一个命名空间 (http://id.loc.gov/vocabulary/...
),因此临时解决方案只是过滤该值:not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))
。从长远来看,我正在研究 nomisma.org,它体现了一种更可持续的 XForms 链接数据词汇管理方法。
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://localhost:8080/exist/apps/xsltforms/xsltforms.xsl" type="text/xsl"?>
<?xsltforms-options debug="yes"?>
<?css-conversion no?>
<?xml-model href="http://www.oxygenxml.com/1999/xhtml/xhtml-xforms.nvdl" schematypens="http://purl.oclc.org/dsdl/nvdl/ns/structure/1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:bf="http://bibframe.org/vocab/"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Editor</title>
<!--Model-->
<xf:model id="rdf-model">
<xf:instance id="graph">
<rdf:RDF>
<bf:Work rdf:about="">
<bf:subject rdf:resource="http://id.loc.gov/vocabulary/geographicAreas/s-ag"></bf:subject>
<bf:subject rdf:resource="http://id.loc.gov/vocabulary/geographicAreas/s-bl"></bf:subject>
<bf:subject rdf:resource=""/>
</bf:Work>
</rdf:RDF>
</xf:instance>
<!-- Template -->
<xf:instance id="bf-Work-template">
<rdf:RDF>
<bf:Work rdf:about="">
<bf:subject rdf:resource="http://id.loc.gov/vocabulary/geographicAreas/s-ag"></bf:subject>
<bf:subject rdf:resource="http://id.loc.gov/vocabulary/geographicAreas/s-bl"></bf:subject>
<bf:subject rdf:resource=""/>
</bf:Work>
</rdf:RDF>
</xf:instance>
</xf:model>
</head>
<body>
<div id="header">
<h1>Editor</h1>
</div>
<div id="forms">
<!-- Repeat for Work entity -->
<xf:repeat nodeset="instance('graph')/bf:Work" id="repeat-Work-graph">
<!-- Repeat bf:subject elements that have a default value. -->
<xf:repeat
nodeset="bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]">
<div style="border:solid black 1px;">
<xf:input
ref="@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']">
<xf:label>Subject</xf:label>
</xf:input>
<!-- Add new bf:subject elements that have a default value -->
<xf:trigger ref=".">
<xf:label>+</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert
nodeset="../bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]"
origin="instance('bf-Work-template')/bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]"
at="last()" position="after"></xf:insert>
</xf:action>
</xf:trigger>
<!-- Delete bf:subject elements that have a default value -->
<xf:trigger
ref=".[count(../bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]) > 1]">
<xf:label>-</xf:label>
<xf:delete ev:event="DOMActivate" nodeset="." at="last()"
if="count(../bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]) > 1"
></xf:delete>
</xf:trigger>
</div>
</xf:repeat>
<!-- Add new bf:subject elements that can take an arbitrary value -->
<xf:trigger ref="bf:subject[not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))]">
<xf:label>+</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="."
origin="instance('bf-Work-template')/bf:Work/bf:subject[not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))]"
at="last()" position="after"></xf:insert>
</xf:action>
</xf:trigger>
<!-- Delete bf:subject elements that can take an arbitrary value -->
<xf:trigger
ref="bf:subject[not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))][count(../bf:subject[not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))]) > 1]">
<xf:label>-</xf:label>
<xf:action ev:event="DOMActivate">
<xf:delete nodeset="../bf:subject[not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))]" at="last()"
if="count(../bf:subject[not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))]) > 1"></xf:delete>
</xf:action>
</xf:trigger>
<!-- Repeat bf:subject elements that can take an arbitrary value -->
<xf:repeat nodeset="bf:subject[not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))]">
<div style="border:solid black 1px;">
<!-- Value of @rdf:resource is updated using jsPlumb library -->
<span class="label">Subject</span>
<br />
<span>Link to:</span>
<br />
<span class="connect-to">Work</span>
<br />
<span class="connect-to">Topic</span>
<br />
<span class="connect-to">Place</span>
</div>
</xf:repeat>
</xf:repeat>
</div>
</body>
</html>
如果您正在寻找一种 XPath 方法来了解某个元素是第一个还是第二个子元素,您可以考虑使用坐标轴,例如 .[preceding-sibling::bf:subject]
我正在尝试在 XForms(eXist-db 中的 XSLTForms 实现)中编辑 RDF/XML,我需要对 xf:repeat
结构中具有相同名称的元素强制执行不同的值约束。例如,我有一个 bf:subject
元素,它可以将默认 URI 作为其 @rdf:resource
属性的值,也可以将任意 URI 链接到表单中定义的其他资源(为简洁起见)我在下面提供的示例中省略了这些)。
在xf:repeat
结构中,如何区分同名元素?我可以使用将 @rdf:resource
的值限制为 xf:model
中指定的默认 URI 的谓词来处理第一种情况,但我找不到一种方法来实现对 [= =13=] 可以采用任意 URI。
注意:第二个嵌套 xf:repeat 中没有表单控件,因为 @rdf:resource 的值是使用单独的 JavaScript 库动态更新的(jsPlumb) 更新 XForms 实例。
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://localhost:8080/exist/apps/xsltforms/xsltforms.xsl" type="text/xsl"?>
<?xsltforms-options debug="yes"?>
<?css-conversion no?>
<?xml-model href="http://www.oxygenxml.com/1999/xhtml/xhtml-xforms.nvdl" schematypens="http://purl.oclc.org/dsdl/nvdl/ns/structure/1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:bf="http://bibframe.org/vocab/"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Editor</title>
<!--Model-->
<xf:model id="rdf-model">
<xf:instance id="graph">
<rdf:RDF>
<bf:Work rdf:about="">
<bf:subject rdf:resource="http://id.loc.gov/vocabulary/geographicAreas/s-ag"></bf:subject>
<bf:subject rdf:resource=""/>
</bf:Work>
</rdf:RDF>
</xf:instance>
<!-- Template -->
<xf:instance id="bf-Work-template">
<rdf:RDF>
<bf:Work rdf:about="">
<bf:subject rdf:resource="http://id.loc.gov/vocabulary/geographicAreas/s-ag"></bf:subject>
<bf:subject rdf:resource=""/>
</bf:Work>
</rdf:RDF>
</xf:instance>
</xf:model>
</head>
<body>
<div id="header">
<h1>Editor</h1>
</div>
<div id="forms">
<!-- Repeat for Work entity -->
<xf:repeat nodeset="instance('graph')/bf:Work" id="repeat-Work-graph">
<!-- Repeat bf:subject elements that have a default value. -->
<xf:repeat
nodeset="bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]">
<div style="border:solid black 1px;">
<xf:input
ref="@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']">
<xf:label>Subject</xf:label>
</xf:input>
<!-- Add new bf:subject elements that have a default value -->
<xf:trigger ref=".">
<xf:label>+</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert
nodeset="../bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]"
origin="instance('bf-Work-template')/bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]"
at="last()" position="after"></xf:insert>
</xf:action>
</xf:trigger>
<!-- Delete bf:subject elements that have a default value -->
<xf:trigger
ref=".[count(../bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]) > 1]">
<xf:label>-</xf:label>
<xf:delete ev:event="DOMActivate" nodeset="." at="last()"
if="count(../bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]) > 1"
></xf:delete>
</xf:trigger>
</div>
</xf:repeat>
<!-- Add new bf:subject elements that can take an arbitrary value -->
<xf:trigger ref="bf:subject[@rdf:resource = '']">
<xf:label>+</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="."
origin="instance('bf-Work-template')/bf:Work/bf:subject[@rdf:resource = '']"
at="last()" position="after"></xf:insert>
</xf:action>
</xf:trigger>
<!-- Delete bf:subject elements that can take an arbitrary value -->
<xf:trigger
ref="bf:subject[@rdf:resource = ''][count(../bf:subject[@rdf:resource = '']) > 1]">
<xf:label>-</xf:label>
<xf:action ev:event="DOMActivate">
<xf:delete nodeset="../bf:subject[@rdf:resource = '']" at="last()"
if="count(../bf:subject[@rdf:resource = '']) > 1"></xf:delete>
</xf:action>
</xf:trigger>
<!-- Repeat bf:subject elements that can take an arbitrary value -->
<xf:repeat nodeset="bf:subject[@rdf:resource = '']">
<div style="border:solid black 1px;">
<!-- Value of @rdf:resource is updated using jsPlumb library -->
<span class="label">Subject</span>
<br />
<span>Link to:</span>
<br />
<span class="connect-to">Work</span>
<br />
<span class="connect-to">Topic</span>
<br />
<span class="connect-to">Place</span>
</div>
</xf:repeat>
</xf:repeat>
</div>
</body>
</html>
目前,默认的 URI 都来自同一个命名空间 (http://id.loc.gov/vocabulary/...
),因此临时解决方案只是过滤该值:not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))
。从长远来看,我正在研究 nomisma.org,它体现了一种更可持续的 XForms 链接数据词汇管理方法。
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://localhost:8080/exist/apps/xsltforms/xsltforms.xsl" type="text/xsl"?>
<?xsltforms-options debug="yes"?>
<?css-conversion no?>
<?xml-model href="http://www.oxygenxml.com/1999/xhtml/xhtml-xforms.nvdl" schematypens="http://purl.oclc.org/dsdl/nvdl/ns/structure/1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:bf="http://bibframe.org/vocab/"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Editor</title>
<!--Model-->
<xf:model id="rdf-model">
<xf:instance id="graph">
<rdf:RDF>
<bf:Work rdf:about="">
<bf:subject rdf:resource="http://id.loc.gov/vocabulary/geographicAreas/s-ag"></bf:subject>
<bf:subject rdf:resource="http://id.loc.gov/vocabulary/geographicAreas/s-bl"></bf:subject>
<bf:subject rdf:resource=""/>
</bf:Work>
</rdf:RDF>
</xf:instance>
<!-- Template -->
<xf:instance id="bf-Work-template">
<rdf:RDF>
<bf:Work rdf:about="">
<bf:subject rdf:resource="http://id.loc.gov/vocabulary/geographicAreas/s-ag"></bf:subject>
<bf:subject rdf:resource="http://id.loc.gov/vocabulary/geographicAreas/s-bl"></bf:subject>
<bf:subject rdf:resource=""/>
</bf:Work>
</rdf:RDF>
</xf:instance>
</xf:model>
</head>
<body>
<div id="header">
<h1>Editor</h1>
</div>
<div id="forms">
<!-- Repeat for Work entity -->
<xf:repeat nodeset="instance('graph')/bf:Work" id="repeat-Work-graph">
<!-- Repeat bf:subject elements that have a default value. -->
<xf:repeat
nodeset="bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]">
<div style="border:solid black 1px;">
<xf:input
ref="@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']">
<xf:label>Subject</xf:label>
</xf:input>
<!-- Add new bf:subject elements that have a default value -->
<xf:trigger ref=".">
<xf:label>+</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert
nodeset="../bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]"
origin="instance('bf-Work-template')/bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]"
at="last()" position="after"></xf:insert>
</xf:action>
</xf:trigger>
<!-- Delete bf:subject elements that have a default value -->
<xf:trigger
ref=".[count(../bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]) > 1]">
<xf:label>-</xf:label>
<xf:delete ev:event="DOMActivate" nodeset="." at="last()"
if="count(../bf:subject[@rdf:resource[. = 'http://id.loc.gov/vocabulary/geographicAreas/s-ag']]) > 1"
></xf:delete>
</xf:trigger>
</div>
</xf:repeat>
<!-- Add new bf:subject elements that can take an arbitrary value -->
<xf:trigger ref="bf:subject[not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))]">
<xf:label>+</xf:label>
<xf:action ev:event="DOMActivate">
<xf:insert nodeset="."
origin="instance('bf-Work-template')/bf:Work/bf:subject[not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))]"
at="last()" position="after"></xf:insert>
</xf:action>
</xf:trigger>
<!-- Delete bf:subject elements that can take an arbitrary value -->
<xf:trigger
ref="bf:subject[not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))][count(../bf:subject[not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))]) > 1]">
<xf:label>-</xf:label>
<xf:action ev:event="DOMActivate">
<xf:delete nodeset="../bf:subject[not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))]" at="last()"
if="count(../bf:subject[not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))]) > 1"></xf:delete>
</xf:action>
</xf:trigger>
<!-- Repeat bf:subject elements that can take an arbitrary value -->
<xf:repeat nodeset="bf:subject[not(starts-with(@rdf:resource, 'http://id.loc.gov/vocabulary/geographicAreas/'))]">
<div style="border:solid black 1px;">
<!-- Value of @rdf:resource is updated using jsPlumb library -->
<span class="label">Subject</span>
<br />
<span>Link to:</span>
<br />
<span class="connect-to">Work</span>
<br />
<span class="connect-to">Topic</span>
<br />
<span class="connect-to">Place</span>
</div>
</xf:repeat>
</xf:repeat>
</div>
</body>
</html>
如果您正在寻找一种 XPath 方法来了解某个元素是第一个还是第二个子元素,您可以考虑使用坐标轴,例如 .[preceding-sibling::bf:subject]