xml FEATURE XML attribute parsing function
diff --git a/src/xml.c b/src/xml.c
index c4bdb4b..d1a2be8 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -179,6 +179,116 @@
return LY_SUCCESS;
}
+/**
+ * @brief Parse input expecting an XML attribute (including XML namespace).
+ *
+ * Input string is not being modified, so the returned values are not NULL-terminated, instead their length
+ * is returned.
+ *
+ * In case of a namespace definition, prefix just contains xmlns string. In case of the default namespace,
+ * prefix is NULL and the attribute name is xmlns.
+ *
+ * @param[in] context XML context to track lines or store errors into libyang context.
+ * @param[in,out] input Input string to process, updated according to the processed/read data so,
+ * when succeeded, it points to the opening quote of the attribute's value..
+ * @param[in] options Currently unused options to modify input processing.
+ * @param[out] prefix Pointer to prefix if present in the attribute name, NULL otherwise.
+ * @param[out] prefix_len Length of the prefix if any.
+ * @param[out] name Attribute name. LY_SUCCESS can be returned with NULL name only in case the
+ * end of the element tag was reached.
+ * @param[out] name_len Length of the element name.
+ * @return LY_ERR values.
+ */
+LY_ERR
+lyxml_get_attribute(struct lyxml_context *context, const char **input, int UNUSED(options),
+ const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
+{
+ struct ly_ctx *ctx = context->ctx; /* shortcut */
+ const char *in = (*input);
+ const char *id;
+ const char *endtag;
+ LY_ERR rc;
+ unsigned int c;
+ size_t endtag_len;
+
+ /* initialize output variables */
+ (*prefix) = (*name) = NULL;
+ (*prefix_len) = (*name_len) = 0;
+
+ /* skip initial whitespaces */
+ ign_xmlws(context, in);
+
+ if (in[0] == '\0') {
+ /* EOF - not expected at this place */
+ return LY_EINVAL;
+ } else if (in[0] == '>' || in[0] == '/') {
+ /* element terminated by > or /> */
+ goto success;
+ }
+
+ /* remember the identifier start before checking its format */
+ id = in;
+ rc = lyxml_check_qname(context, &in, &c, &endtag_len);
+ LY_CHECK_RET(rc);
+ if (c == ':') {
+ /* we have prefixed identifier */
+ endtag = in - endtag_len;
+
+ rc = lyxml_check_qname(context, &in, &c, &endtag_len);
+ LY_CHECK_RET(rc);
+
+ (*prefix) = id;
+ (*prefix_len) = endtag - id;
+ id = endtag + 1;
+ }
+ if (!is_xmlws(c) && c != '=') {
+ in = in - endtag_len;
+ LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(in), in, "whitespace or '='");
+ return LY_EVALID;
+ }
+ in = in - endtag_len;
+ (*name) = id;
+ (*name_len) = in - id;
+
+ /* eat '=' and stop at the value beginning */
+ ign_xmlws(context, in);
+ if (in[0] != '=') {
+ LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(in), in, "'='");
+ return LY_EVALID;
+ }
+ ++in;
+ ign_xmlws(context, in);
+ if (in[0] != '\'' && in[0] != '"') {
+ LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(in), in, "either single or double quotation mark");
+ return LY_EVALID;
+ }
+
+success:
+ /* move caller's input */
+ (*input) = in;
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse input expecting an XML element.
+ *
+ * Able to silently skip comments, PIs and CData. DOCTYPE is not parsable, so it is reported as LY_EVALID error.
+ * If '<' is not found in input, LY_EINVAL is returned (but no error is logged), so it is possible to continue
+ * with parsing input as text content.
+ *
+ * Input string is not being modified, so the returned values are not NULL-terminated, instead their length
+ * is returned.
+ *
+ * @param[in] context XML context to track lines or store errors into libyang context.
+ * @param[in,out] input Input string to process, updated according to the processed/read data.
+ * @param[in] options Currently unused options to modify input processing.
+ * @param[out] prefix Pointer to prefix if present in the element name, NULL otherwise.
+ * @param[out] prefix_len Length of the prefix if any.
+ * @param[out] name Element name. LY_SUCCESS can be returned with NULL name only in case the
+ * end of the input string was reached (EOF).
+ * @param[out] name_len Length of the element name.
+ * @return LY_ERR values.
+ */
LY_ERR
lyxml_get_element(struct lyxml_context *context, const char **input, int UNUSED(options),
const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
@@ -192,7 +302,6 @@
bool loop = true;
unsigned int c;
LY_ERR rc;
- uint32_t x;
/* initialize output variables */
(*prefix) = (*name) = NULL;
@@ -260,9 +369,8 @@
}
if (!is_xmlws(c) && c != '/' && c != '>') {
in = in - endtag_len;
- x = 0;
- memcpy(&x, in, endtag_len);
- LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INCHAR, x);
+ LOGVAL(ctx, LY_VLOG_LINE, &context->line, LY_VCODE_INSTREXP, LY_VCODE_INSTREXP_len(in), in,
+ "whitespace or element tag termination ('>' or '/>'");
return LY_EVALID;
}
in = in - endtag_len;