Skip to content

Commit 7161d3a

Browse files
authored
Merge pull request #113 from strictdoc-project/stanislaw/develop
spec_object_parser: a slot for XHTML attribute stripped from namespace info
2 parents d348cf9 + d9061aa commit 7161d3a

10 files changed

Lines changed: 132 additions & 10 deletions

File tree

reqif/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.0.29"
1+
__version__ = "0.0.32"

reqif/helpers/lxml.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ def my_escape_title(string: str) -> str:
4545
# FIXME: Would be great to find a better solution for this.
4646
def stringify_namespaced_children(node, namespace_tag=None) -> str:
4747
if namespace_tag is None:
48+
assert (
49+
len(node.nsmap) > 0
50+
), f"This method must be called on a namespaced tag:\n{dump_xml_node(node)}" # noqa: E501
4851
nskey = next(iter(node.nsmap.keys()))
4952
else:
5053
nskey = namespace_tag
@@ -79,19 +82,30 @@ def _stringify_reqif_ns_node(node):
7982
return string
8083

8184

82-
# https://stackoverflow.com/a/4624146/598057
85+
# https://stackoverflow.com/a/28173933/598057
8386
def stringify_children(node):
8487
return "".join(
8588
chunk
8689
for chunk in chain(
8790
(node.text,),
8891
chain(
8992
*(
90-
(tostring(child, encoding=str, with_tail=False), child.tail)
93+
(
94+
tostring(
95+
child,
96+
encoding=str,
97+
with_tail=False,
98+
pretty_print=False,
99+
),
100+
child.tail,
101+
)
91102
for child in node.getchildren()
92103
)
93104
),
94-
(node.tail,),
105+
# The original snippet prints the node tail for some reason which is
106+
# surprisingly unnecessary.
107+
# (node.tail,), # noqa: ERA001
108+
(None,),
95109
)
96110
if chunk
97111
)
@@ -111,6 +125,12 @@ def lxml_convert_from_reqif_ns_xhtml_string(lxml_node) -> str:
111125
).rstrip()
112126

113127

128+
def lxml_convert_children_from_reqif_ns_xhtml_string(lxml_node) -> str:
129+
lxml_node_deep_copy = deepcopy(lxml_node)
130+
lxml_strip_namespace_from_xml(lxml_node_deep_copy, full=True)
131+
return stringify_children(lxml_node_deep_copy)
132+
133+
114134
def is_self_closed_tag(xml):
115135
# The tag cannot be closed if it has children or has a non-None text.
116136
if len(xml.getchildren()) > 0:

reqif/models/reqif_spec_object.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@
66

77
@auto_described
88
class SpecObjectAttribute:
9-
def __init__(
9+
def __init__( # pylint: disable=too-many-arguments
1010
self,
1111
attribute_type: SpecObjectAttributeType,
1212
definition_ref: str,
1313
value: Union[str, List[str]],
14+
value_stripped_xhtml: Optional[str] = None,
1415
xml_node: Optional[Any] = None,
1516
):
1617
self.attribute_type: SpecObjectAttributeType = attribute_type
1718
self.definition_ref: str = definition_ref
1819
self.value: Union[str, List[str]] = value
20+
# Only for XHTML attributes: A value stripped of the
21+
# <xhtml:...> namespace. <xhtml:div> becomes <div>...
22+
self.value_stripped_xhtml: Optional[str] = value_stripped_xhtml
1923
self.xml_node: Optional[Any] = xml_node
2024

2125

reqif/parsers/spec_object_parser.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33

44
from lxml import etree
55

6-
from reqif.helpers.lxml import stringify_namespaced_children
6+
from reqif.helpers.lxml import (
7+
lxml_convert_children_from_reqif_ns_xhtml_string,
8+
stringify_children,
9+
stringify_namespaced_children,
10+
)
11+
from reqif.helpers.string.xhtml_indent import reqif_unindent_xhtml_string
712
from reqif.models.reqif_spec_object import (
813
ReqIFSpecObject,
914
SpecObjectAttribute,
@@ -201,17 +206,33 @@ def parse(spec_object_xml) -> ReqIFSpecObject:
201206
)
202207
elif attribute_xml.tag == "ATTRIBUTE-VALUE-XHTML":
203208
the_value = attribute_xml.find("THE-VALUE")
204-
attribute_value = stringify_namespaced_children(the_value)
209+
210+
# Edge: There are not <xhtml:...> or <reqif-xhtml...> tags.
211+
if len(the_value.nsmap) > 0:
212+
attribute_value = stringify_namespaced_children(the_value)
213+
attribute_value_stripped_xhtml = (
214+
reqif_unindent_xhtml_string(
215+
lxml_convert_children_from_reqif_ns_xhtml_string(
216+
the_value
217+
)
218+
)
219+
)
220+
else:
221+
attribute_value = stringify_children(the_value)
222+
attribute_value_stripped_xhtml = (
223+
reqif_unindent_xhtml_string(attribute_value)
224+
)
205225
attribute_definition_ref = (
206226
attribute_xml.find("DEFINITION")
207227
.find("ATTRIBUTE-DEFINITION-XHTML-REF")
208228
.text
209229
)
210230
attribute = SpecObjectAttribute(
211-
xml_node=attribute_xml,
212231
attribute_type=SpecObjectAttributeType.XHTML,
213232
definition_ref=attribute_definition_ref,
214233
value=attribute_value,
234+
value_stripped_xhtml=attribute_value_stripped_xhtml,
235+
xml_node=attribute_xml,
215236
)
216237
else:
217238
raise NotImplementedError(etree.tostring(attribute_xml))

tasks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,8 @@ def check(_):
181181

182182

183183
@task
184-
def release(context, username=None, password=None):
185-
user_password = f"-u{username} -p{password}" if username is not None else ""
184+
def release(context, password=None):
185+
user_password = f"-ustanislaw -p{password}" if password is not None else ""
186186
command = f"""
187187
rm -rfv dist/ &&
188188
python3 -m build &&

tests/integration/reqif/SPEC-OBJECTS/02_XHTML_attribute/sample.reqif renamed to tests/integration/reqif/SPEC-OBJECTS/ATTRIBUTE-VALUE-XHTML/01_XHTML_attribute/sample.reqif

File renamed without changes.

tests/integration/reqif/SPEC-OBJECTS/02_XHTML_attribute/test.itest renamed to tests/integration/reqif/SPEC-OBJECTS/ATTRIBUTE-VALUE-XHTML/01_XHTML_attribute/test.itest

File renamed without changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<REQ-IF xmlns="http://www.omg.org/spec/ReqIF/20110401/reqif.xsd" xmlns:configuration="http://eclipse.org/rmf/pror/toolextensions/1.0" xmlns:xhtml="http://www.w3.org/1999/xhtml">
3+
<CORE-CONTENT>
4+
<REQ-IF-CONTENT>
5+
<SPEC-OBJECTS>
6+
<SPEC-OBJECT IDENTIFIER="TEST_SPEC_OBJECT_IDENTIFIER" LAST-CHANGE="2021-10-15T11:34:36.007+02:00">
7+
<VALUES>
8+
<ATTRIBUTE-VALUE-XHTML>
9+
<DEFINITION>
10+
<ATTRIBUTE-DEFINITION-XHTML-REF>_gFhrXWojEeuExICsU7Acmg</ATTRIBUTE-DEFINITION-XHTML-REF>
11+
</DEFINITION>
12+
<THE-VALUE>
13+
Some text without any tags.
14+
</THE-VALUE>
15+
</ATTRIBUTE-VALUE-XHTML>
16+
</VALUES>
17+
<TYPE>
18+
<SPEC-OBJECT-TYPE-REF>TEST_SPEC_OBJECT_TYPE_IDENTIFIER_FUNCTIONAL</SPEC-OBJECT-TYPE-REF>
19+
</TYPE>
20+
</SPEC-OBJECT>
21+
</SPEC-OBJECTS>
22+
</REQ-IF-CONTENT>
23+
</CORE-CONTENT>
24+
</REQ-IF>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
RUN: mkdir -p %S/output
2+
RUN: %reqif passthrough %S/sample.reqif %S/output/sample.reqif
3+
RUN: diff %S/sample.reqif %S/output/sample.reqif
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from reqif.parser import ReqIFParser
2+
3+
4+
def test_01_indenting_unintended_xhtml():
5+
input_reqif = """\
6+
<?xml version="1.0" encoding="UTF-8"?>
7+
<REQ-IF xmlns="http://www.omg.org/spec/ReqIF/20110401/reqif.xsd" xmlns:configuration="http://eclipse.org/rmf/pror/toolextensions/1.0" xmlns:xhtml="http://www.w3.org/1999/xhtml">
8+
<CORE-CONTENT>
9+
<REQ-IF-CONTENT>
10+
<SPEC-OBJECTS>
11+
<SPEC-OBJECT IDENTIFIER="TEST_SPEC_OBJECT_IDENTIFIER" LAST-CHANGE="2021-10-15T11:34:36.007+02:00">
12+
<VALUES>
13+
<ATTRIBUTE-VALUE-XHTML>
14+
<DEFINITION>
15+
<ATTRIBUTE-DEFINITION-XHTML-REF>_gFhrXWojEeuExICsU7Acmg</ATTRIBUTE-DEFINITION-XHTML-REF>
16+
</DEFINITION>
17+
<THE-VALUE>
18+
<xhtml:div>
19+
<xhtml:p style=" font-style: italic">Delay <xhtml:span style="text-decoration: underline;">&lt;= 5s</xhtml:span></xhtml:p>
20+
</xhtml:div>
21+
</THE-VALUE>
22+
</ATTRIBUTE-VALUE-XHTML>
23+
</VALUES>
24+
<TYPE>
25+
<SPEC-OBJECT-TYPE-REF>TEST_SPEC_OBJECT_TYPE_IDENTIFIER_FUNCTIONAL</SPEC-OBJECT-TYPE-REF>
26+
</TYPE>
27+
</SPEC-OBJECT>
28+
</SPEC-OBJECTS>
29+
</REQ-IF-CONTENT>
30+
</CORE-CONTENT>
31+
</REQ-IF>
32+
""" # noqa: E501
33+
34+
expected_stripped_xhtml = """\
35+
<div>
36+
<p style=" font-style: italic">Delay <span style="text-decoration: underline;">&lt;= 5s</span></p>
37+
</div>\
38+
""" # noqa: E501
39+
40+
reqif_bundle = ReqIFParser.parse_from_string(input_reqif)
41+
spec_object = reqif_bundle.get_spec_object_by_ref(
42+
"TEST_SPEC_OBJECT_IDENTIFIER"
43+
)
44+
45+
assert (
46+
spec_object.attribute_map[
47+
"_gFhrXWojEeuExICsU7Acmg"
48+
].value_stripped_xhtml
49+
== expected_stripped_xhtml
50+
)

0 commit comments

Comments
 (0)